From criswell at cs.uiuc.edu Mon Aug 9 10:36:02 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Mon, 9 Aug 2004 10:36:02 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/lib/Transforms/ExprTypeConvert.cpp LevelRaise.cpp Message-ID: <200408091536.KAA03623@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms: ExprTypeConvert.cpp updated: 1.96 -> 1.96.2.1 LevelRaise.cpp updated: 1.100 -> 1.100.2.1 --- Log message: Merged in changes Chris commited over the weekend. Merge done on August 9, 2004. --- Diffs of the changes: (+4 -4) Index: llvm/lib/Transforms/ExprTypeConvert.cpp diff -u llvm/lib/Transforms/ExprTypeConvert.cpp:1.96 llvm/lib/Transforms/ExprTypeConvert.cpp:1.96.2.1 --- llvm/lib/Transforms/ExprTypeConvert.cpp:1.96 Thu Jul 29 07:17:34 2004 +++ llvm/lib/Transforms/ExprTypeConvert.cpp Mon Aug 9 10:35:51 2004 @@ -151,7 +151,7 @@ // If it's a constant... all constants can be converted to a different // type. // - if (Constant *CPV = dyn_cast(V)) + if (isa(V) && !isa(V)) return true; CTMap[V] = Ty; @@ -984,10 +984,9 @@ unsigned OtherIdx = (OldVal == I->getOperand(0)) ? 1 : 0; Value *OtherOp = I->getOperand(OtherIdx); + Res->setOperand(!OtherIdx, NewVal); Value *NewOther = ConvertExpressionToType(OtherOp, NewTy, VMC, TD); - Res->setOperand(OtherIdx, NewOther); - Res->setOperand(!OtherIdx, NewVal); break; } case Instruction::Shl: Index: llvm/lib/Transforms/LevelRaise.cpp diff -u llvm/lib/Transforms/LevelRaise.cpp:1.100 llvm/lib/Transforms/LevelRaise.cpp:1.100.2.1 --- llvm/lib/Transforms/LevelRaise.cpp:1.100 Thu Jul 29 07:17:33 2004 +++ llvm/lib/Transforms/LevelRaise.cpp Mon Aug 9 10:35:51 2004 @@ -302,7 +302,8 @@ // Make sure the source doesn't change type ConvertedTypes[Src] = Src->getType(); if (ValueConvertibleToType(CI, Src->getType(), ConvertedTypes, TD)) { - PRINT_PEEPHOLE3("CAST-DEST-EXPR-CONV:in ", *Src, *CI, *BB->getParent()); + //PRINT_PEEPHOLE3("CAST-DEST-EXPR-CONV:in ", *Src, *CI, + // *BB->getParent()); DEBUG(std::cerr << "\nCONVERTING EXPR TYPE:\n"); { // ValueMap must be destroyed before function verified! From criswell at cs.uiuc.edu Mon Aug 9 10:36:02 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Mon, 9 Aug 2004 10:36:02 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/lib/Transforms/IPO/Inliner.cpp Message-ID: <200408091536.KAA03626@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: Inliner.cpp updated: 1.20 -> 1.20.2.1 --- Log message: Merged in changes Chris commited over the weekend. Merge done on August 9, 2004. --- Diffs of the changes: (+24 -24) Index: llvm/lib/Transforms/IPO/Inliner.cpp diff -u llvm/lib/Transforms/IPO/Inliner.cpp:1.20 llvm/lib/Transforms/IPO/Inliner.cpp:1.20.2.1 --- llvm/lib/Transforms/IPO/Inliner.cpp:1.20 Thu Jul 29 12:28:42 2004 +++ llvm/lib/Transforms/IPO/Inliner.cpp Mon Aug 9 10:35:51 2004 @@ -54,8 +54,8 @@ E = CalleeNode->end(); I != E; ++I) CallerNode->addCalledFunction(*I); - // If we inlined the last possible call site to the function, - // delete the function body now. + // If we inlined the last possible call site to the function, delete the + // function body now. if (Callee->use_empty() && Callee->hasInternalLinkage() && !SCCFunctions.count(Callee)) { DEBUG(std::cerr << " -> Deleting dead function: " @@ -64,7 +64,7 @@ // Remove any call graph edges from the callee to its callees. while (CalleeNode->begin() != CalleeNode->end()) CalleeNode->removeCallEdgeTo(*(CalleeNode->end()-1)); - + // Removing the node for callee from the call graph and delete it. delete CG.removeFunctionFromModule(CalleeNode); ++NumDeleted; @@ -167,27 +167,27 @@ // from the program. Insert the dead ones in the FunctionsToRemove set. for (CallGraph::iterator I = CG.begin(), E = CG.end(); I != E; ++I) { CallGraphNode *CGN = I->second; - Function *F = CGN ? CGN->getFunction() : 0; - - // If the only remaining users of the function are dead constants, - // remove them. - if (F) F->removeDeadConstantUsers(); - - if (F && (F->hasLinkOnceLinkage() || F->hasInternalLinkage()) && - F->use_empty()) { - - // Remove any call graph edges from the function to its callees. - while (CGN->begin() != CGN->end()) - CGN->removeCallEdgeTo(*(CGN->end()-1)); - - // If the function has external linkage (basically if it's a linkonce - // function) remove the edge from the external node to the callee - // node. - if (!F->hasInternalLinkage()) - CG.getExternalCallingNode()->removeCallEdgeTo(CGN); - - // Removing the node for callee from the call graph and delete it. - FunctionsToRemove.insert(CGN); + if (Function *F = CGN ? CGN->getFunction() : 0) { + // If the only remaining users of the function are dead constants, + // remove them. + bool HadDeadConstantUsers = !F->use_empty(); + F->removeDeadConstantUsers(); + + if ((F->hasLinkOnceLinkage() || F->hasInternalLinkage()) && + F->use_empty()) { + // Remove any call graph edges from the function to its callees. + while (CGN->begin() != CGN->end()) + CGN->removeCallEdgeTo(*(CGN->end()-1)); + + // If the function has external linkage (basically if it's a linkonce + // function) remove the edge from the external node to the callee + // node. + if (!F->hasInternalLinkage() || HadDeadConstantUsers) + CG.getExternalCallingNode()->removeCallEdgeTo(CGN); + + // Removing the node for callee from the call graph and delete it. + FunctionsToRemove.insert(CGN); + } } } From brukman at cs.uiuc.edu Mon Aug 9 12:24:42 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 12:24:42 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/Makefile Message-ID: <200408091724.MAA08743@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: Makefile updated: 1.8 -> 1.9 --- Log message: Generate a code emitter for PowerPC as well, this will be used in the JIT. --- Diffs of the changes: (+5 -1) Index: llvm/lib/Target/PowerPC/Makefile diff -u llvm/lib/Target/PowerPC/Makefile:1.8 llvm/lib/Target/PowerPC/Makefile:1.9 --- llvm/lib/Target/PowerPC/Makefile:1.8 Thu Aug 5 13:34:15 2004 +++ llvm/lib/Target/PowerPC/Makefile Mon Aug 9 12:24:32 2004 @@ -15,7 +15,7 @@ # Make sure that tblgen is run, first thing. $(SourceDepend): PowerPCGenRegisterInfo.h.inc PowerPCGenRegisterNames.inc \ PowerPCGenRegisterInfo.inc PowerPCGenInstrNames.inc \ - PowerPCGenInstrInfo.inc + PowerPCGenInstrInfo.inc PowerPCGenCodeEmitter.inc TDFILES = $(SourceDir)/$(TARGET).td $(wildcard $(SourceDir)/*.td) \ $(SourceDir)/../Target.td @@ -40,5 +40,9 @@ @echo "Building $(TARGET).td instruction information with tblgen" $(VERB) $(TBLGEN) -I $(BUILD_SRC_DIR) $< -gen-instr-desc -o $@ +$(TARGET)GenCodeEmitter.inc:: $(TDFILES) $(TBLGEN) + @echo "Building $(TARGET).td code emitter" + $(VERB) $(TBLGEN) -I $(SourceDir) $< -gen-emitter -o $@ + clean:: $(VERB) rm -f *.inc From brukman at cs.uiuc.edu Mon Aug 9 12:24:44 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 12:24:44 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td PowerPCInstrInfo.td Message-ID: <200408091724.MAA08749@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCInstrFormats.td updated: 1.3 -> 1.4 PowerPCInstrInfo.td updated: 1.14 -> 1.15 --- Log message: Use instruction formats as defined in the PowerPC ISA manual --- Diffs of the changes: (+475 -611) Index: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.3 llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.4 --- llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.3 Wed Aug 4 16:18:57 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Mon Aug 9 12:24:04 2004 @@ -38,27 +38,12 @@ def Imm15 : Format<21>; def Vpr : Format<22>; -class PPC32Inst : Instruction { - field bits<32> Inst; - bits<3> ArgCount; - bits<5> Arg0Type; - bits<5> Arg1Type; - bits<5> Arg2Type; - bits<5> Arg3Type; - bits<5> Arg4Type; - bit PPC64; - bit VMX; - - let Namespace = "PPC32"; -} - //===----------------------------------------------------------------------===// // // PowerPC instruction formats class PPC32I opcode, bit ppc64, bit vmx> : Instruction { field bits<32> Inst; - field bits<6> Opcode = opcode; bits<3> ArgCount; bits<5> Arg0Type; @@ -70,46 +55,60 @@ bit VMX = vmx; let Name = name; - let Inst{0-5} = Opcode; + let Namespace = "PPC32"; + let Inst{0-5} = opcode; } -class XForm_base_r3xo opcode, bits<10> xo, bit ppc64, - bit vmx> : PPC32I { - let ArgCount = 3; - field bits<5> A; - field bits<5> B; - field bits<5> C; - field bits<10> D = xo; - field bit Rc = 0; +// 1.7.1 I-Form +class IForm opcode, bit aa, bit lk, bit ppc64, bit vmx> + : PPC32I { + field bits<24> LI; - let ArgCount = 3; - let Arg0Type = Gpr.Value; - let Arg1Type = Gpr.Value; - let Arg2Type = Gpr.Value; + let ArgCount = 1; + let Arg0Type = Imm24.Value; + let Arg1Type = 0; + let Arg2Type = 0; let Arg3Type = 0; let Arg4Type = 0; - let Inst{6-10} = A; - let Inst{11-15} = B; - let Inst{16-20} = C; - let Inst{21-30} = D; - let Inst{31} = Rc; + let Inst{6-29} = LI; + let Inst{30} = aa; + let Inst{31} = lk; } -class XForm_6 opcode, bits<10> xo, bit rc, bit ppc64, - bit vmx> : XForm_base_r3xo { - let Rc = rc; -} +// 1.7.2 B-Form +class BForm opcode, bit aa, bit lk, bit ppc64, bit vmx> + : PPC32I { + field bits<5> BO; + field bits<5> BI; + field bits<14> BD; -class XForm_7 opcode, bits<10> xo, bit ppc64, bit vmx> - : XForm_6; + let ArgCount = 3; + let Arg0Type = Imm5.Value; + let Arg1Type = Imm5.Value; + let Arg2Type = PCRelimm14.Value; + let Arg3Type = 0; + let Arg4Type = 0; -class XForm_10 opcode, bits<10> xo, bit rc, bit ppc64, - bit vmx> : XForm_base_r3xo { - let Rc = rc; + let Inst{6-10} = BO; + let Inst{11-15} = BI; + let Inst{16-29} = BD; + let Inst{30} = aa; + let Inst{31} = lk; +} + +class BForm_ext opcode, bit aa, bit lk, bits<5> bo, + bits<5> bi, bit ppc64, bit vmx> + : BForm { + let ArgCount = 2; let Arg2Type = Imm5.Value; + let Arg1Type = PCRelimm14.Value; + let Arg2Type = 0; + let BO = bo; + let BI = bi; } +// 1.7.4 D-Form class DForm_base opcode, bit ppc64, bit vmx> : PPC32I { field bits<5> A; @@ -130,7 +129,8 @@ class DForm_1 opcode, bit ppc64, bit vmx> : DForm_base { - let Arg2Type = Zimm16.Value; + let Arg1Type = Disimm16.Value; + let Arg2Type = Gpr0.Value; } class DForm_2 opcode, bit ppc64, bit vmx> @@ -139,6 +139,7 @@ class DForm_2_r0 opcode, bit ppc64, bit vmx> : DForm_base { let Arg1Type = Gpr0.Value; + let B = 0; } // Currently we make the use/def reg distinction in ISel, not tablegen @@ -148,539 +149,400 @@ class DForm_4 opcode, bit ppc64, bit vmx> : DForm_1; -class DForm_7 opcode, bit ppc64, bit vmx> - : DForm_base { - let Arg1Type = Imm5.Value; +class DForm_4_zero opcode, bit ppc64, bit vmx> + : DForm_1 { + let ArgCount = 0; + let Arg0Type = 0; + let Arg1Type = 0; + let Arg2Type = 0; + let A = 0; + let B = 0; + let C = 0; } -//===----------------------------------------------------------------------===// - -class PPC32InstPattern1 opconstant0, bits<5> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 2; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = 0; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<16> operand1; - +class DForm_5 opcode, bit ppc64, bit vmx> + : PPC32I { + field bits<3> BF; + field bits<1> L; + field bits<5> RA; + field bits<16> I; + + let ArgCount = 4; + let Arg0Type = Imm3.Value; + let Arg1Type = Imm1.Value; + let Arg2Type = Gpr.Value; + let Arg3Type = Simm16.Value; + let Arg4Type = 0; - let Inst {31-26} = opconstant0; - let Inst {20-16} = opconstant1; - let Inst {25-21} = operand0; - let Inst {15-0} = operand1; + let Inst{6-8} = BF; + let Inst{9} = 0; + let Inst{10} = L; + let Inst{11-15} = RA; + let Inst{16-31} = I; } -class PPC32InstPattern2 opconstant0, bits<11> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 3; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = OperandType2.Value; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<5> operand1; - bits<5> operand2; - - - let Inst {31-26} = opconstant0; - let Inst {10-0} = opconstant1; - let Inst {25-21} = operand0; - let Inst {20-16} = operand1; - let Inst {15-11} = operand2; +class DForm_5_ext opcode, bit ppc64, bit vmx> + : DForm_5 { + let L = 0; } -class PPC32InstPattern3 opconstant0, bits<16> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 2; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = 0; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<5> operand1; - - - let Inst {31-26} = opconstant0; - let Inst {15-0} = opconstant1; - let Inst {25-21} = operand0; - let Inst {20-16} = operand1; +class DForm_6 opcode, bit ppc64, bit vmx> + : DForm_5 { + let Arg3Type = Zimm16.Value; } -class PPC32InstPattern6 opconstant0, bits<2> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 1; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = 0; - let Arg2Type = 0; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<24> operand0; - - - let Inst {31-26} = opconstant0; - let Inst {1-0} = opconstant1; - let Inst {25-2} = operand0; +class DForm_6_ext opcode, bit ppc64, bit vmx> + : DForm_6 { + let L = 0; } -class PPC32InstPattern7 opconstant0, bits<2> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 3; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = OperandType2.Value; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<5> operand1; - bits<14> operand2; - - - let Inst {31-26} = opconstant0; - let Inst {1-0} = opconstant1; - let Inst {25-21} = operand0; - let Inst {20-16} = operand1; - let Inst {15-2} = operand2; +class DForm_7 opcode, bit ppc64, bit vmx> + : DForm_base { + let Arg1Type = Imm5.Value; } -class PPC32InstPattern9 opconstant0, bits<2> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 2; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = 0; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<14> operand1; - - - let Inst {31-21} = opconstant0; - let Inst {1-0} = opconstant1; - let Inst {20-16} = operand0; - let Inst {15-2} = operand1; +class DForm_8 opcode, bit ppc64, bit vmx> + : DForm_1 { + let Arg0Type = Fpr.Value; } -class PPC32InstPattern11 opconstant0, bits<11> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 1; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = 0; - let Arg2Type = 0; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<2> operand0; - - - let Inst {31-13} = opconstant0; - let Inst {10-0} = opconstant1; - let Inst {12-11} = operand0; +class DForm_9 opcode, bit ppc64, bit vmx> + : DForm_1 { + let Arg0Type = Fpr.Value; } -class PPC32InstPattern13 opconstant0, bits<1> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 4; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = OperandType2.Value; - let Arg3Type = OperandType3.Value; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<3> operand0; - bits<1> operand1; - bits<5> operand2; - bits<16> operand3; +// 1.7.6 X-Form +class XForm_base_r3xo opcode, bits<10> xo, bit rc, + bit ppc64, bit vmx> : PPC32I { + let ArgCount = 3; + field bits<5> ST; + field bits<5> A; + field bits<5> B; + let ArgCount = 3; + let Arg0Type = Gpr.Value; + let Arg1Type = Gpr.Value; + let Arg2Type = Gpr.Value; + let Arg3Type = 0; + let Arg4Type = 0; - let Inst {31-26} = opconstant0; - let Inst {22} = opconstant1; - let Inst {25-23} = operand0; - let Inst {21} = operand1; - let Inst {20-16} = operand2; - let Inst {15-0} = operand3; + let Inst{6-10} = ST; + let Inst{11-15} = A; + let Inst{16-20} = B; + let Inst{21-30} = xo; + let Inst{31} = rc; +} + +class XForm_1 opcode, bits<10> xo, bit ppc64, + bit vmx> : XForm_base_r3xo; + +class XForm_5 opcode, bits<10> xo, bit ppc64, + bit vmx> : XForm_base_r3xo { + let ArgCount = 1; + let Arg1Type = 0; + let Arg2Type = 0; + let A = 0; + let B = 0; } -class PPC32InstPattern14 opconstant0, bits<2> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 3; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = OperandType2.Value; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<3> operand0; - bits<5> operand1; - bits<16> operand2; +class XForm_6 opcode, bits<10> xo, bit rc, bit ppc64, + bit vmx> : XForm_base_r3xo; +class XForm_7 opcode, bits<10> xo, bit ppc64, bit vmx> + : XForm_base_r3xo; - let Inst {31-26} = opconstant0; - let Inst {22-21} = opconstant1; - let Inst {25-23} = operand0; - let Inst {20-16} = operand1; - let Inst {15-0} = operand2; -} +class XForm_8 opcode, bits<10> xo, bit ppc64, bit vmx> + : XForm_base_r3xo; -class PPC32InstPattern15 opconstant0, bits<1> opconstant1, bits<11> opconstant2, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 4; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = OperandType2.Value; - let Arg3Type = OperandType3.Value; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<3> operand0; - bits<1> operand1; - bits<5> operand2; - bits<5> operand3; - - - let Inst {31-26} = opconstant0; - let Inst {22} = opconstant1; - let Inst {10-0} = opconstant2; - let Inst {25-23} = operand0; - let Inst {21} = operand1; - let Inst {20-16} = operand2; - let Inst {15-11} = operand3; +class XForm_10 opcode, bits<10> xo, bit rc, bit ppc64, + bit vmx> : XForm_base_r3xo { + let Arg2Type = Imm5.Value; } -class PPC32InstPattern16 opconstant0, bits<2> opconstant1, bits<11> opconstant2, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 3; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = OperandType2.Value; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<3> operand0; - bits<5> operand1; - bits<5> operand2; - +class XForm_11 opcode, bits<10> xo, bit rc, bit ppc64, + bit vmx> : XForm_base_r3xo { + let ArgCount = 2; + let Arg2Type = 0; + let B = 0; +} - let Inst {31-26} = opconstant0; - let Inst {22-21} = opconstant1; - let Inst {10-0} = opconstant2; - let Inst {25-23} = operand0; - let Inst {20-16} = operand1; - let Inst {15-11} = operand2; +class XForm_16 opcode, bits<10> xo, bit ppc64, bit vmx> + : PPC32I { + field bits<3> BF; + field bits<1> L; + field bits<5> RA; + field bits<5> RB; + + let ArgCount = 4; + let Arg0Type = Imm3.Value; + let Arg1Type = Imm1.Value; + let Arg2Type = Gpr.Value; + let Arg3Type = Gpr.Value; + let Arg4Type = 0; + + let Inst{6-8} = BF; + let Inst{9} = 0; + let Inst{10} = L; + let Inst{11-15} = RA; + let Inst{16-20} = RB; + let Inst{21-30} = xo; + let Inst{31} = 0; } -class PPC32InstPattern17 opconstant0, bits<16> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 2; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = 0; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<5> operand1; +class XForm_16_ext opcode, bits<10> xo, bit ppc64, bit vmx> + : XForm_16 { + let L = 0; +} +class XForm_17 opcode, bits<10> xo, bit ppc64, bit vmx> + : PPC32I { + field bits<3> BF; + field bits<5> FRA; + field bits<5> FRB; + + let ArgCount = 3; + let Arg0Type = Imm3.Value; + let Arg1Type = Fpr.Value; + let Arg2Type = Fpr.Value; + let Arg3Type = 0; + let Arg4Type = 0; - let Inst {31-26} = opconstant0; - let Inst {15-0} = opconstant1; - let Inst {20-16} = operand0; - let Inst {25-21} = operand1; + let Inst{6-8} = BF; + let Inst{9-10} = 0; + let Inst{11-15} = FRA; + let Inst{16-20} = FRB; + let Inst{21-30} = xo; + let Inst{31} = 0; } -class PPC32InstPattern18 opconstant0, bits<5> opconstant1, bits<6> opconstant2, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 3; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = OperandType2.Value; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<5> operand1; - bits<5> operand2; +class XForm_25 opcode, bits<10> xo, bit ppc64, + bit vmx> : XForm_base_r3xo { + let Arg0Type = Fpr.Value; + let Arg1Type = Gpr0.Value; +} +class XForm_26 opcode, bits<10> xo, bit rc, bit ppc64, + bit vmx> : XForm_base_r3xo { + let ArgCount = 2; + let Arg0Type = Fpr.Value; + let Arg1Type = Fpr.Value; + let Arg2Type = 0; + let A = 0; +} - let Inst {31-26} = opconstant0; - let Inst {15-11} = opconstant1; - let Inst {5-0} = opconstant2; - let Inst {25-21} = operand0; - let Inst {20-16} = operand1; - let Inst {10-6} = operand2; +class XForm_28 opcode, bits<10> xo, bit ppc64, + bit vmx> : XForm_base_r3xo { + let Arg0Type = Fpr.Value; + let Arg1Type = Gpr0.Value; } -class PPC32InstPattern19 opconstant0, bits<6> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 4; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = OperandType2.Value; - let Arg3Type = OperandType3.Value; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<5> operand1; - bits<5> operand2; - bits<5> operand3; +// 1.7.7 XL-Form +class XLForm_1 opcode, bits<10> xo, bit ppc64, bit vmx> + : XForm_base_r3xo { + let Arg0Type = Imm5.Value; + let Arg1Type = Imm5.Value; + let Arg2Type = Imm5.Value; +} +class XLForm_2 opcode, bits<10> xo, bit lk, bit ppc64, + bit vmx> : PPC32I { + field bits<5> BO; + field bits<5> BI; + field bits<2> BH; + + let ArgCount = 3; + let Arg0Type = Imm5.Value; + let Arg1Type = Imm5.Value; + let Arg2Type = Imm2.Value; + let Arg3Type = 0; + let Arg4Type = 0; - let Inst {31-26} = opconstant0; - let Inst {5-0} = opconstant1; - let Inst {25-21} = operand0; - let Inst {20-16} = operand1; - let Inst {10-6} = operand2; - let Inst {15-11} = operand3; + let Inst{6-10} = BO; + let Inst{11-15} = BI; + let Inst{16-18} = 0; + let Inst{19-20} = BH; + let Inst{21-30} = xo; + let Inst{31} = lk; +} + +class XLForm_2_ext opcode, bits<10> xo, bits<5> bo, + bits<5> bi, bit lk, bit ppc64, bit vmx> + : XLForm_2 { + let ArgCount = 0; + let Arg0Type = 0; + let Arg1Type = 0; + let Arg2Type = 0; + let BO = bo; + let BI = bi; + let BH = 0; } -class PPC32InstPattern20 opconstant0, bits<5> opconstant1, bits<11> opconstant2, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 2; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = 0; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<5> operand1; +// 1.7.8 XFX-Form +class XFXForm_1 opcode, bits<10> xo, bit ppc64, bit vmx> + : PPC32I { + field bits<5> ST; + field bits<10> SPR; + let ArgCount = 2; + let Arg0Type = Imm5.Value; + let Arg1Type = Gpr.Value; + let Arg2Type = 0; + let Arg3Type = 0; + let Arg4Type = 0; - let Inst {31-26} = opconstant0; - let Inst {20-16} = opconstant1; - let Inst {10-0} = opconstant2; - let Inst {25-21} = operand0; - let Inst {15-11} = operand1; + let Inst{6-10} = ST; + let Inst{11-20} = SPR; + let Inst{21-30} = xo; + let Inst{31} = 0; } -class PPC32InstPattern21 opconstant0, bits<21> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 1; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = 0; - let Arg2Type = 0; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; +class XFXForm_1_ext opcode, bits<10> xo, bits<10> spr, + bit ppc64, bit vmx> : XFXForm_1 { + let ArgCount = 1; + let Arg0Type = Gpr.Value; + let Arg1Type = 0; + let SPR = spr; +} +class XFXForm_7 opcode, bits<10> xo, bit ppc64, bit vmx> + : XFXForm_1; - let Inst {31-26} = opconstant0; - let Inst {20-0} = opconstant1; - let Inst {25-21} = operand0; +class XFXForm_7_ext opcode, bits<10> xo, bits<10> spr, + bit ppc64, bit vmx> : XFXForm_7 { + let ArgCount = 1; + let Arg0Type = Gpr.Value; + let Arg1Type = 0; + let SPR = spr; } -class PPC32InstPattern25 opconstant0, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 3; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = OperandType2.Value; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<16> operand1; - bits<5> operand2; +// 1.7.11 XO-Form +class XOForm_1 opcode, bits<9> xo, bit oe, bit rc, + bit ppc64, bit vmx> : PPC32I { + field bits<5> RT; + field bits<5> RA; + field bits<5> RB; + + let ArgCount = 3; + let Arg0Type = Gpr.Value; + let Arg1Type = Gpr.Value; + let Arg2Type = Gpr.Value; + let Arg3Type = 0; + let Arg4Type = 0; + let Inst{6-10} = RT; + let Inst{11-15} = RA; + let Inst{16-20} = RB; + let Inst{21} = oe; + let Inst{22-30} = xo; + let Inst{31} = rc; +} + +// This is a reversal of the two operands, used notably by extended ops SUB*: +// sub x, y, z == subf x, z, y +// subc x, y, z == subfc x, z, y +class XOForm_1_rev opcode, bits<9> xo, bit oe, bit rc, + bit ppc64, bit vmx> + : XOForm_1 { + let Inst{11-15} = RB; + let Inst{16-20} = RA; +} + +class XOForm_2 opcode, bits<9> xo, bit rc, bit ppc64, + bit vmx> : XOForm_1; + +class XOForm_3 opcode, bits<9> xo, bit oe, bit rc, + bit ppc64, bit vmx> : XOForm_1 { + let RB = 0; +} + +// 1.7.12 A-Form +class AForm_1 opcode, bits<5> xo, bit rc, bit ppc64, + bit vmx> : PPC32I { + let ArgCount = 4; + field bits<5> FRT; + field bits<5> FRA; + field bits<5> FRB; + field bits<5> FRC; + + let Arg0Type = Fpr.Value; + let Arg1Type = Fpr.Value; + let Arg2Type = Fpr.Value; + let Arg3Type = Fpr.Value; + let Arg4Type = 0; - let Inst {31-26} = opconstant0; - let Inst {25-21} = operand0; - let Inst {15-0} = operand1; - let Inst {20-16} = operand2; + let Inst{6-10} = FRT; + let Inst{11-15} = FRA; + let Inst{16-20} = FRB; + let Inst{21-25} = FRC; + let Inst{26-30} = xo; + let Inst{31} = rc; } -class PPC32InstPattern32 opconstant0, bits<1> opconstant1, bits<12> opconstant2, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 2; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = 0; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<8> operand1; - +class AForm_2 opcode, bits<5> xo, bit rc, bit ppc64, + bit vmx> : AForm_1 { + let ArgCount = 3; + let Arg3Type = 0; + let FRC = 0; +} - let Inst {31-26} = opconstant0; - let Inst {20} = opconstant1; - let Inst {11-0} = opconstant2; - let Inst {25-21} = operand0; - let Inst {19-12} = operand1; +class AForm_3 opcode, bits<5> xo, bit rc, bit ppc64, + bit vmx> : AForm_1 { + let ArgCount = 3; + let Arg3Type = 0; + let FRB = 0; } -class PPC32InstPattern33 opconstant0, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 0; - let PPC64 = ppc64; - let VMX =vmx; +class AForm_4 opcode, bits<5> xo, bit rc, bit ppc64, + bit vmx> : AForm_1 { + let ArgCount = 2; + let Arg2Type = 0; + let Arg3Type = 0; + let FRA = 0; + let FRC = 0; +} - let Arg0Type = 0; - let Arg1Type = 0; - let Arg2Type = 0; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; +// 1.7.13 M-Form +class MForm_1 opcode, bit rc, bit ppc64, bit vmx> + : PPC32I { + let ArgCount = 5; + field bits<5> RS; + field bits<5> RA; + field bits<5> RB; + field bits<5> MB; + field bits<5> ME; + let Arg0Type = Gpr.Value; + let Arg1Type = Gpr.Value; + let Arg2Type = Gpr.Value; + let Arg3Type = Imm5.Value; + let Arg4Type = Imm5.Value; - let Inst {31-0} = opconstant0; + let Inst{6-10} = RS; + let Inst{11-15} = RA; + let Inst{16-20} = RB; + let Inst{21-25} = MB; + let Inst{26-30} = ME; + let Inst{31} = rc; } -class PPC32InstPattern34 opconstant0, bits<1> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 5; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = OperandType2.Value; - let Arg3Type = OperandType3.Value; - let Arg4Type = OperandType4.Value; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<5> operand1; - bits<5> operand2; - bits<5> operand3; - bits<5> operand4; - - - let Inst {31-26} = opconstant0; - let Inst {0} = opconstant1; - let Inst {20-16} = operand0; - let Inst {25-21} = operand1; - let Inst {15-11} = operand2; - let Inst {10-6} = operand3; - let Inst {5-1} = operand4; +class MForm_2 opcode, bit rc, bit ppc64, bit vmx> + : MForm_1 { + let Arg2Type = Imm5.Value; } -class PPC32InstPattern35 opconstant0, bits<11> opconstant1, bit ppc64, bit vmx> : PPC32Inst { - let Name = name; - let ArgCount = 3; - let PPC64 = ppc64; - let VMX =vmx; - - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType1.Value; - let Arg2Type = OperandType2.Value; - let Arg3Type = 0; - let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<5> operand1; - bits<5> operand2; - - - let Inst {31-26} = opconstant0; - let Inst {10-0} = opconstant1; - let Inst {25-21} = operand0; - let Inst {15-11} = operand1; - let Inst {20-16} = operand2; -} +//===----------------------------------------------------------------------===// -class PPC32InstPatternPseudo : PPC32Inst { +class Pseudo : PPC32I { let Name = name; let ArgCount = 0; let PPC64 = 0; let VMX = 0; - let Arg0Type = OperandType0.Value; - let Arg1Type = OperandType0.Value; - let Arg2Type = OperandType0.Value; - let Arg3Type = OperandType0.Value; + let Arg0Type = Pseudo.Value; + let Arg1Type = Pseudo.Value; + let Arg2Type = Pseudo.Value; + let Arg3Type = Pseudo.Value; let Arg4Type = 0; - let PPC64 = 0; - let VMX = 0; - bits<5> operand0; - bits<5> operand1; - bits<5> operand2; - bits<4> operand3; - let Inst {31-0} = 0; } Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.14 llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.15 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.14 Tue Aug 3 15:23:44 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.td Mon Aug 9 12:24:04 2004 @@ -7,49 +7,53 @@ // //===----------------------------------------------------------------------===// // +// This file describes the subset of the 32-bit PowerPC instruction set, as used +// by the PowerPC instruction selector. // //===----------------------------------------------------------------------===// include "PowerPCInstrFormats.td" let isTerminator = 1, isReturn = 1 in - def BLR : PPC32InstPattern11 <"blr", Imm2, 160768, 32, 0, 0>; + def BLR : XLForm_2_ext<"blr", 19, 16, 20, 31, 1, 0, 0>; // Pseudo-instructions: -def PHI : PPC32InstPatternPseudo<"PHI", Pseudo>; // PHI node... -def ADJCALLSTACKDOWN : PPC32InstPatternPseudo<"ADJCALLSTACKDOWN", Pseudo>; -def ADJCALLSTACKUP : PPC32InstPatternPseudo<"ADJCALLSTACKUP", Pseudo>; +def PHI : Pseudo<"PHI">; // PHI node... +def ADJCALLSTACKDOWN : Pseudo<"ADJCALLSTACKDOWN">; +def ADJCALLSTACKUP : Pseudo<"ADJCALLSTACKUP">; let Defs = [LR] in - def MovePCtoLR : PPC32InstPatternPseudo<"MovePCtoLR", Pseudo>; -def IMPLICIT_DEF : PPC32InstPatternPseudo<"IMPLICIT_DEF", Pseudo>; + def MovePCtoLR : Pseudo<"MovePCtoLR">; +def IMPLICIT_DEF : Pseudo<"IMPLICIT_DEF">; def LOADLoIndirect : DForm_2_r0 <"lwz", 14, 0, 0>; def LOADLoDirect : DForm_2_r0<"la", 14, 0, 0>; def LOADHiAddr : DForm_2_r0<"addis", 15, 0, 0>; -def ADDI : DForm_2_r0<"addi", 14, 0, 0>; -def SUBI : DForm_2_r0 <"subi", 14, 0, 0>; -def LI : PPC32InstPattern1 <"li", Gpr, Simm16, 14, 0, 0, 0>; -def ADDIS : DForm_2_r0 <"addis", 15, 0, 0>; -def LIS : PPC32InstPattern1 <"lis", Gpr, Simm16, 15, 0, 0, 0>; -def ADDIC : DForm_2<"addic", 12, 0, 0>; -def ADD : PPC32InstPattern2 <"add", Gpr, Gpr, Gpr, 31, 532, 0, 0>; -def ADDC : PPC32InstPattern2 <"addc", Gpr, Gpr, Gpr, 31, 20, 0, 0>; -def ADDE : PPC32InstPattern2 <"adde", Gpr, Gpr, Gpr, 31, 276, 0, 0>; -def ADDZE : PPC32InstPattern3 <"addze", Gpr, Gpr, 31, 404, 0, 0>; -def ANDIo : DForm_4<"andi.", 28, 0, 0>; +def ADDI : DForm_2<"addi", 14, 0, 0>; +def ADDIS : DForm_2<"addis", 15, 0, 0>; +def SUBI : DForm_2<"subi", 14, 0, 0>; +def LI : DForm_2_r0<"li", 14, 0, 0>; +def LIS : DForm_2_r0<"lis", 15, 0, 0>; +def ADDIC : DForm_2<"addic", 12, 0, 0>; +def ADD : XOForm_1<"add", 31, 266, 0, 0, 0, 0>; +def ADDC : XOForm_1<"addc", 31, 10, 0, 0, 0, 0>; +def ADDE : XOForm_1<"adde", 31, 138, 0, 0, 0, 0>; +def ADDZE : XOForm_3<"addze", 31, 202, 0, 0, 0, 0>; +def ANDIo : DForm_4<"andi.", 28, 0, 0>; def AND : XForm_6<"and", 31, 28, 0, 0, 0>; def ANDC : XForm_6<"andc", 31, 60, 0, 0, 0>; let isBranch = 1, isTerminator = 1 in { - def COND_BRANCH : PPC32InstPatternPseudo<"COND_BRANCH", Pseudo>; - def B : PPC32InstPattern6 <"b", PCRelimm24, 18, 0, 0, 0>; - def BLT : PPC32InstPattern9 <"blt", Crf, PCRelimm14, 524, 0, 0, 0>; - def BLE : PPC32InstPattern9 <"ble", Crf, PCRelimm14, 516, 0, 0, 0>; - def BEQ : PPC32InstPattern9 <"beq", Crf, PCRelimm14, 524, 0, 0, 0>; - def BGE : PPC32InstPattern9 <"bge", Crf, PCRelimm14, 516, 0, 0, 0>; - def BGT : PPC32InstPattern9 <"bgt", Crf, PCRelimm14, 524, 0, 0, 0>; - def BNE : PPC32InstPattern9 <"bne", Crf, PCRelimm14, 516, 0, 0, 0>; + def COND_BRANCH : Pseudo<"COND_BRANCH">; + def B : IForm<"b", 18, 0, 0, 0, 0>; + // FIXME: 4*CR# needs to be added to the BI field! + // This will only work for CR0 as it stands now + def BLT : BForm_ext<"blt", 16, 0, 0, 12, 0, 0, 0>; + def BLE : BForm_ext<"ble", 16, 0, 0, 4, 1, 0, 0>; + def BEQ : BForm_ext<"beq", 16, 0, 0, 12, 2, 0, 0>; + def BGE : BForm_ext<"bge", 16, 0, 0, 4, 0, 0, 0>; + def BGT : BForm_ext<"bgt", 16, 0, 0, 12, 1, 0, 0>; + def BNE : BForm_ext<"bne", 16, 0, 0, 4, 2, 0, 0>; } let isBranch = 1, isTerminator = 1, isCall = 1, @@ -59,99 +63,97 @@ LR,XER,CTR, CR0,CR1,CR5,CR6,CR7] in { // Convenient aliases for call instructions - def CALLpcrel : PPC32InstPattern6 <"bl", PCRelimm24, 18, 1, 0, 0>; - def CALLindirect : PPC32InstPattern3 <"bctrl", Imm5, Imm5, 19, 1057, 0, 0>; - - def BL : PPC32InstPattern6 <"bl", PCRelimm24, 18, 1, 0, 0>; + def CALLpcrel : IForm<"bl", 18, 0, 1, 0, 0>; + def CALLindirect : XLForm_2_ext<"bctrl", 19, 528, 20, 31, 1, 0, 0>; } -def CMPI : PPC32InstPattern13 <"cmpi", Imm3, Imm1, Gpr, Simm16, 11, 0, 0, 0>; -def CMPWI : PPC32InstPattern14 <"cmpwi", Imm3, Gpr, Simm16, 11, 0, 0, 0>; -def CMPW : PPC32InstPattern16 <"cmpw", Imm3, Gpr, Gpr, 31, 0, 0, 0, 0>; -def CMPLI : PPC32InstPattern13 <"cmpli", Imm3, Imm1, Gpr, Zimm16, 10, 0, 0, 0>; -def CMPLWI : PPC32InstPattern14 <"cmplwi", Imm3, Gpr, Zimm16, 10, 0, 0, 0>; -def CMPL : PPC32InstPattern15 <"cmpl", Imm3, Imm1, Gpr, Gpr, 31, 0, 64, 0, 0>; -def CMPLW : PPC32InstPattern16 <"cmplw", Imm3, Gpr, Gpr, 31, 0, 64, 0, 0>; -def CRAND : PPC32InstPattern2 <"crand", Imm5, Imm5, Imm5, 19, 514, 0, 0>; -def CRANDC : PPC32InstPattern2 <"crandc", Imm5, Imm5, Imm5, 19, 258, 0, 0>; -def CRNOR : PPC32InstPattern2 <"crnor", Imm5, Imm5, Imm5, 19, 66, 0, 0>; -def CROR : PPC32InstPattern2 <"cror", Imm5, Imm5, Imm5, 19, 898, 0, 0>; -def DIVW : PPC32InstPattern2 <"divw", Gpr, Gpr, Gpr, 31, 982, 0, 0>; -def DIVWU : PPC32InstPattern2 <"divwu", Gpr, Gpr, Gpr, 31, 918, 0, 0>; -def EXTSB : PPC32InstPattern17 <"extsb", Gpr, Gpr, 31, 1908, 0, 0>; -def EXTSH : PPC32InstPattern17 <"extsh", Gpr, Gpr, 31, 1844, 0, 0>; -def FADD : PPC32InstPattern2 <"fadd", Fpr, Fpr, Fpr, 63, 42, 0, 0>; -def FADDS : PPC32InstPattern2 <"fadds", Fpr, Fpr, Fpr, 59, 42, 0, 0>; -def FSUB : PPC32InstPattern2 <"fsub", Fpr, Fpr, Fpr, 63, 40, 0, 0>; -def FSUBS : PPC32InstPattern2 <"fsubs", Fpr, Fpr, Fpr, 59, 40, 0, 0>; -def FMUL : PPC32InstPattern18 <"fmul", Fpr, Fpr, Fpr, 63, 0, 18, 0, 0>; -def FMULS : PPC32InstPattern18 <"fmuls", Fpr, Fpr, Fpr, 59, 0, 18, 0, 0>; -def FDIV : PPC32InstPattern2 <"fdiv", Fpr, Fpr, Fpr, 63, 36, 0, 0>; -def FDIVS : PPC32InstPattern2 <"fdivs", Fpr, Fpr, Fpr, 59, 36, 0, 0>; -def FMR : PPC32InstPattern20 <"fmr", Fpr, Fpr, 63, 0, 144, 0, 0>; -def FNEG : PPC32InstPattern20 <"fneg", Fpr, Fpr, 63, 0, 80, 0, 0>; -def FRSP : PPC32InstPattern20 <"frsp", Fpr, Fpr, 63, 0, 24, 0, 0>; -def FSEL : PPC32InstPattern19 <"fsel", Fpr, Fpr, Fpr, Fpr, 63, 14, 0, 0>; -def FCTIW : PPC32InstPattern20 <"fctiw", Fpr, Fpr, 63, 0, 28, 0, 0>; -def FCTIWZ : PPC32InstPattern20 <"fctiwz", Fpr, Fpr, 63, 0, 30, 0, 0>; -def FCMPU : PPC32InstPattern16 <"fcmpu", Imm3, Fpr, Fpr, 63, 0, 0, 0, 0>; -def LBZ : PPC32InstPattern25 <"lbz", Gpr, Disimm16, Gpr0, 34, 0, 0>; -def LBZX : PPC32InstPattern2 <"lbzx", Gpr, Gpr0, Gpr, 31, 174, 0, 0>; -def LHZ : PPC32InstPattern25 <"lhz", Gpr, Disimm16, Gpr0, 40, 0, 0>; -def LHZX : PPC32InstPattern2 <"lhzx", Gpr, Gpr0, Gpr, 31, 558, 0, 0>; -def LHA : PPC32InstPattern25 <"lha", Gpr, Disimm16, Gpr0, 42, 0, 0>; -def LHAX : PPC32InstPattern2 <"lhax", Gpr, Gpr0, Gpr, 31, 686, 0, 0>; -def LWZ : PPC32InstPattern25 <"lwz", Gpr, Disimm16, Gpr0, 32, 0, 0>; -def LWZX : PPC32InstPattern2 <"lwzx", Gpr, Gpr0, Gpr, 31, 46, 0, 0>; -def LMW : PPC32InstPattern25 <"lmw", Gpr, Disimm16, Gpr0, 46, 0, 0>; -def STMW : PPC32InstPattern25 <"stmw", Gpr, Disimm16, Gpr0, 47, 0, 0>; -def LFS : PPC32InstPattern25 <"lfs", Fpr, Disimm16, Gpr0, 48, 0, 0>; -def LFSX : PPC32InstPattern2 <"lfsx", Fpr, Gpr0, Gpr, 31, 46, 0, 0>; -def LFD : PPC32InstPattern25 <"lfd", Fpr, Disimm16, Gpr0, 50, 0, 0>; -def LFDX : PPC32InstPattern2 <"lfdx", Fpr, Gpr0, Gpr, 31, 174, 0, 0>; -def MFCR : PPC32InstPattern32 <"mfcr", Gpr, Imm8, 31, 0, 38, 0, 0>; -def MFLR : PPC32InstPattern21 <"mflr", Gpr, 31, 524966, 0, 0>; -def MFCTR : PPC32InstPattern21 <"mfctr", Gpr, 31, 590502, 0, 0>; -def MTLR : PPC32InstPattern21 <"mtlr", Gpr, 31, 525222, 0, 0>; -def MTCTR : PPC32InstPattern21 <"mtctr", Gpr, 31, 590758, 0, 0>; -def MULLW : PPC32InstPattern2 <"mullw", Gpr, Gpr, Gpr, 31, 470, 0, 0>; -def MULHWU : PPC32InstPattern2 <"mulhwu", Gpr, Gpr, Gpr, 31, 22, 0, 0>; +def CMPI : DForm_5<"cmpi", 11, 0, 0>; +def CMPWI : DForm_5_ext<"cmpwi", 11, 0, 0>; +def CMPW : XForm_16 <"cmpw", 31, 0, 0, 0>; +def CMPLI : DForm_6<"cmpli", 10, 0, 0>; +def CMPLWI : DForm_6_ext<"cmplwi", 10, 0, 0>; +def CMPL : XForm_16<"cmpl", 31, 32, 0, 0>; +def CMPLW : XForm_16_ext<"cmplw", 31, 32, 0, 0>; +def CRAND : XLForm_1<"crand", 19, 257, 0, 0>; +def CRANDC : XLForm_1<"crandc", 19, 129, 0, 0>; +def CRNOR : XLForm_1<"crnor", 19, 33, 0, 0>; +def CROR : XLForm_1<"cror", 19, 449, 0, 0>; +def DIVW : XOForm_1<"divw", 31, 491, 0, 0, 0, 0>; +def DIVWU : XOForm_1<"divwu", 31, 459, 0, 0, 0, 0>; +def EXTSB : XForm_11<"extsb", 31, 954, 0, 0, 0>; +def EXTSH : XForm_11<"extsh", 31, 922, 0, 0, 0>; +def FADD : AForm_2<"fadd", 63, 21, 0, 0, 0>; +def FADDS : AForm_2<"fadds", 59, 21, 0, 0, 0>; +def FSUB : AForm_2<"fsub", 63, 20, 0, 0, 0>; +def FSUBS : AForm_2<"fsubs", 59, 20, 0, 0, 0>; +def FMUL : AForm_3<"fmul", 63, 25, 0, 0, 0>; +def FMULS : AForm_3<"fmuls", 59, 25, 0, 0, 0>; +def FDIV : AForm_2<"fdiv", 63, 18, 0, 0, 0>; +def FDIVS : AForm_2<"fdivs", 59, 18, 0, 0, 0>; +def FMR : XForm_26<"fmr", 63, 72, 0, 0, 0>; +def FNEG : XForm_26<"fneg", 63, 80, 0, 0, 0>; +def FRSP : XForm_26<"frsp", 63, 12, 0, 0, 0>; +def FSEL : AForm_1<"fsel", 63, 23, 0, 0, 0>; +def FCTIW : XForm_26<"fctiw", 63, 14, 0, 0, 0>; +def FCTIWZ : XForm_26<"fctiwz", 63, 15, 0, 0, 0>; +def FCMPU : XForm_17<"fcmpu", 63, 0, 0, 0>; +def LBZ : DForm_1<"lbz", 35, 0, 0>; +def LBZX : XForm_1<"lbzx", 31, 87, 0, 0>; +def LHZ : DForm_1<"lhz", 40, 0, 0>; +def LHZX : XForm_1<"lhzx", 31, 279, 0, 0>; +def LHA : DForm_1<"lha", 42, 0, 0>; +def LHAX : XForm_1<"lhax", 31, 343, 0, 0>; +def LWZ : DForm_1<"lwz", 32, 0, 0>; +def LWZX : XForm_1<"lwzx", 31, 23, 0, 0>; +def LMW : DForm_1<"lmw", 46, 0, 0>; +def STMW : DForm_3<"stmw", 47, 0, 0>; +def LFS : DForm_8<"lfs", 48, 0, 0>; +def LFSX : XForm_25<"lfsx", 31, 535, 0, 0>; +def LFD : DForm_8<"lfd", 50, 0, 0>; +def LFDX : XForm_25<"lfdx", 31, 599, 0, 0>; +def MFCR : XForm_5<"mfcr", 31, 19, 0, 0>; +def MFLR : XFXForm_1_ext<"mflr", 31, 399, 8, 0, 0>; +def MFCTR : XFXForm_1_ext<"mfctr", 31, 399, 9, 0, 0>; +def MTLR : XFXForm_7_ext<"mtlr", 31, 467, 8, 0, 0>; +def MTCTR : XFXForm_7_ext<"mtctr", 31, 467, 9, 0, 0>; +def MULLW : XOForm_1<"mullw", 31, 235, 0, 0, 0, 0>; +def MULHWU : XOForm_2<"mulhwu", 31, 11, 0, 0, 0>; def NAND : XForm_6<"nand", 31, 476, 0, 0, 0>; -def NEG : PPC32InstPattern3 <"neg", Gpr, Gpr, 31, 208, 0, 0>; +def NEG : XOForm_3<"neg", 31, 104, 0, 0, 0, 0>; def NOR : XForm_6<"nor", 31, 124, 0, 0, 0>; -def NOP : PPC32InstPattern33 <"nop", 1610612736, 0, 0>; +def NOP : DForm_4_zero<"nop", 24, 0, 0>; def ORI : DForm_4<"ori", 24, 0, 0>; def ORIS : DForm_4<"oris", 25, 0, 0>; def OR : XForm_6<"or", 31, 444, 0, 0, 0>; def ORo : XForm_6<"or.", 31, 444, 1, 0, 0>; -def RLWINM : PPC32InstPattern34 <"rlwinm", Gpr, Gpr, Imm5, Imm5, Imm5, 21, 0, 0, 0>; -def RLWNM : PPC32InstPattern34 <"rlwnm", Gpr, Gpr, Gpr, Imm5, Imm5, 23, 0, 0, 0>; -def RLWIMI : PPC32InstPattern34 <"rlwimi", Gpr, Gpr, Imm5, Imm5, Imm5, 20, 0, 0, 0>; +def RLWINM : MForm_2<"rlwinm", 21, 0, 0, 0>; +def RLWNM : MForm_1<"rlwnm", 23, 0, 0, 0>; +def RLWIMI : MForm_2<"rlwimi", 20, 0, 0, 0>; def SLW : XForm_6<"slw", 31, 24, 0, 0, 0>; def SRW : XForm_6<"srw", 31, 24, 0, 0, 0>; def SRAWI : XForm_10<"srawi", 31, 824, 0, 0, 0>; def SRAW : XForm_6<"sraw", 31, 280, 0, 0, 0>; -def STB : PPC32InstPattern25 <"stb", Gpr, Disimm16, Gpr0, 38, 0, 0>; -def STBU : PPC32InstPattern25 <"stbu", Gpr, Disimm16, Gpr, 39, 0, 0>; -def STBX : PPC32InstPattern2 <"stbx", Gpr, Gpr0, Gpr, 31, 430, 0, 0>; -def STH : PPC32InstPattern25 <"sth", Gpr, Disimm16, Gpr0, 44, 0, 0>; -def STHU : PPC32InstPattern25 <"sthu", Gpr, Disimm16, Gpr, 45, 0, 0>; -def STHX : PPC32InstPattern2 <"sthx", Gpr, Gpr0, Gpr, 31, 814, 0, 0>; -def STW : PPC32InstPattern25 <"stw", Gpr, Disimm16, Gpr0, 36, 0, 0>; -def STWU : PPC32InstPattern25 <"stwu", Gpr, Disimm16, Gpr, 37, 0, 0>; -def STWX : PPC32InstPattern2 <"stwx", Gpr, Gpr0, Gpr, 31, 302, 0, 0>; -def STWUX : PPC32InstPattern2 <"stwux", Gpr, Gpr, Gpr, 31, 366, 0, 0>; -def STDX : PPC32InstPattern2 <"stdx", Gpr, Gpr0, Gpr, 31, 298, 1, 0>; -def STFS : PPC32InstPattern25 <"stfs", Fpr, Disimm16, Gpr0, 52, 0, 0>; -def STFSX : PPC32InstPattern2 <"stfsx", Fpr, Gpr0, Gpr, 31, 302, 0, 0>; -def STFD : PPC32InstPattern25 <"stfd", Fpr, Disimm16, Gpr0, 54, 0, 0>; +def STB : DForm_3<"stb", 38, 0, 0>; +def STBU : DForm_3<"stbu", 39, 0, 0>; +def STBX : XForm_8<"stbx", 31, 215, 0, 0>; +def STH : DForm_3<"sth", 44, 0, 0>; +def STHU : DForm_3<"sthu", 45, 0, 0>; +def STHX : XForm_8<"sthx", 31, 407, 0, 0>; +def STW : DForm_3<"stw", 36, 0, 0>; +def STWU : DForm_3<"stwu", 37, 0, 0>; +def STWX : XForm_8<"stwx", 31, 151, 0, 0>; +def STWUX : XForm_8<"stwux", 31, 183, 0, 0>; +def STDX : XForm_8<"stdx", 31, 149, 1, 0>; +def STFS : DForm_9<"stfs", 52, 0, 0>; +def STFSX : XForm_28<"stfsx", 31, 302, 0, 0>; +def STFD : DForm_9<"stfd", 54, 0, 0>; def SUBFIC : DForm_2<"subfic", 8, 0, 0>; -def SUB : PPC32InstPattern35 <"sub", Gpr, Gpr, Gpr, 31, 80, 0, 0>; -def SUBF : PPC32InstPattern2 <"subf", Gpr, Gpr, Gpr, 31, 80, 0, 0>; -def SUBC : PPC32InstPattern35 <"subc", Gpr, Gpr, Gpr, 31, 16, 0, 0>; -def SUBFC : PPC32InstPattern2 <"subfc", Gpr, Gpr, Gpr, 31, 16, 0, 0>; -def SUBFE : PPC32InstPattern2 <"subfe", Gpr, Gpr, Gpr, 31, 272, 0, 0>; -def SUBFZE : PPC32InstPattern3 <"subfze", Gpr, Gpr, 31, 400, 0, 0>; +def SUB : XOForm_1_rev<"sub", 31, 40, 0, 0, 0, 0>; +def SUBF : XOForm_1<"subf", 31, 40, 0, 0, 0, 0>; +def SUBC : XOForm_1_rev<"subc", 31, 8, 0, 0, 0, 0>; +def SUBFC : XOForm_1<"subfc", 31, 8, 0, 0, 0, 0>; +def SUBFE : XOForm_1<"subfe", 31, 136, 0, 0, 0, 0>; +def SUBFZE : XOForm_3<"subfze", 31, 200, 0, 0, 0, 0>; def XORI : DForm_4<"xori", 26, 0, 0>; def XORIS : DForm_4<"xoris", 27, 0, 0>; def XOR : XForm_6<"xor", 31, 316, 0, 0, 0>; From brukman at cs.uiuc.edu Mon Aug 9 12:46:17 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 12:46:17 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/Target.td Message-ID: <200408091746.MAA15041@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target: Target.td updated: 1.29 -> 1.30 --- Log message: Classes need to have a prefix name, so that they can be tacked on to the pieces that TableGen creates for them, e.g. CodeEmitter, AsmPrinter, etc. --- Diffs of the changes: (+1 -0) Index: llvm/lib/Target/Target.td diff -u llvm/lib/Target/Target.td:1.29 llvm/lib/Target/Target.td:1.30 --- llvm/lib/Target/Target.td:1.29 Sun Aug 1 04:36:44 2004 +++ llvm/lib/Target/Target.td Mon Aug 9 12:46:06 2004 @@ -108,6 +108,7 @@ class Instruction { string Name = ""; // The opcode string for this instruction string Namespace = ""; + string ClassPrefix = ""; dag OperandList; // An dag containing the MI operand list. string AsmString = ""; // The .s format to print the instruction with. From brukman at cs.uiuc.edu Mon Aug 9 12:46:36 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 12:46:36 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Message-ID: <200408091746.MAA15055@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCInstrFormats.td updated: 1.4 -> 1.5 --- Log message: Define a ClassPrefix for PowerPC. --- Diffs of the changes: (+1 -0) Index: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.4 llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.5 --- llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.4 Mon Aug 9 12:24:04 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Mon Aug 9 12:46:26 2004 @@ -56,6 +56,7 @@ let Name = name; let Namespace = "PPC32"; + let ClassPrefix = "PowerPC"; let Inst{0-5} = opcode; } From brukman at cs.uiuc.edu Mon Aug 9 12:46:59 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 12:46:59 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9.td Message-ID: <200408091746.MAA15070@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9.td updated: 1.33 -> 1.34 --- Log message: Define the ClassPrefix for SparcV9. --- Diffs of the changes: (+1 -0) Index: llvm/lib/Target/SparcV9/SparcV9.td diff -u llvm/lib/Target/SparcV9/SparcV9.td:1.33 llvm/lib/Target/SparcV9/SparcV9.td:1.34 --- llvm/lib/Target/SparcV9/SparcV9.td:1.33 Thu Jul 1 23:57:35 2004 +++ llvm/lib/Target/SparcV9/SparcV9.td Mon Aug 9 12:46:49 2004 @@ -24,6 +24,7 @@ field bits<32> Inst; let Namespace = "V9"; + let ClassPrefix = "SparcV9"; bits<2> op; let Inst{31-30} = op; // Top two bits are the 'op' field From brukman at cs.uiuc.edu Mon Aug 9 12:47:56 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 12:47:56 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/CodeEmitterGen.cpp Message-ID: <200408091747.MAA15090@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: CodeEmitterGen.cpp updated: 1.31 -> 1.32 --- Log message: * Use Classname and ClassPrefix instead of hard-coded V9 values * Simplify code and shorten lines by not recomputing values --- Diffs of the changes: (+7 -8) Index: llvm/utils/TableGen/CodeEmitterGen.cpp diff -u llvm/utils/TableGen/CodeEmitterGen.cpp:1.31 llvm/utils/TableGen/CodeEmitterGen.cpp:1.32 --- llvm/utils/TableGen/CodeEmitterGen.cpp:1.31 Wed Aug 4 17:07:54 2004 +++ llvm/utils/TableGen/CodeEmitterGen.cpp Mon Aug 9 12:47:45 2004 @@ -23,8 +23,9 @@ EmitSourceFileHeader("Machine Code Emitter", o); - std::string Namespace = "V9::"; - std::string ClassName = "SparcV9CodeEmitter::"; + std::string Namespace = Insts[0]->getValueAsString("Namespace") + "::"; + std::string ClassName = Insts[0]->getValueAsString("ClassPrefix") + + "CodeEmitter::"; //const std::string &Namespace = Inst->getValue("Namespace")->getName(); o << "unsigned " << ClassName @@ -177,14 +178,12 @@ // Scan through the field looking for bit initializers of the current // variable... for (int i = FieldInitializer->getNumBits()-1; i >= 0; --i) { - if (BitInit *BI = dynamic_cast(FieldInitializer->getBit(i))) - { + Init *I = FieldInitializer->getBit(i); + if (BitInit *BI = dynamic_cast(I)) { DEBUG(o << " // bit init: f: " << f << ", i: " << i << "\n"); - } else if (UnsetInit *UI = - dynamic_cast(FieldInitializer->getBit(i))) { + } else if (UnsetInit *UI = dynamic_cast(I)) { DEBUG(o << " // unset init: f: " << f << ", i: " << i << "\n"); - } else if (VarBitInit *VBI = - dynamic_cast(FieldInitializer->getBit(i))) { + } else if (VarBitInit *VBI = dynamic_cast(I)) { TypedInit *TI = VBI->getVariable(); if (VarInit *VI = dynamic_cast(TI)) { // If the bits of the field are laid out consecutively in the From lattner at cs.uiuc.edu Mon Aug 9 13:29:36 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 9 Aug 2004 13:29:36 -0500 Subject: [llvm-commits] CVS: llvm-gcc/gcc/Makefile.in Message-ID: <200408091829.NAA23682@apoc.cs.uiuc.edu> Changes in directory llvm-gcc/gcc: Makefile.in updated: 1.3 -> 1.4 --- Log message: Eliminate the need to hack out .s files from the target build dirs. --- Diffs of the changes: (+8 -2) Index: llvm-gcc/gcc/Makefile.in diff -u llvm-gcc/gcc/Makefile.in:1.3 llvm-gcc/gcc/Makefile.in:1.4 --- llvm-gcc/gcc/Makefile.in:1.3 Thu Feb 5 10:05:44 2004 +++ llvm-gcc/gcc/Makefile.in Mon Aug 9 13:29:24 2004 @@ -1113,8 +1113,14 @@ # # Build libgcc.a. -LIB2ADD = $(LIB2FUNCS_EXTRA) -LIB2ADD_ST = $(LIB2FUNCS_STATIC_EXTRA) +### +### For LLVM GCC, we do not want to add any target-specific .s files or other +### gunk to libgcc. +### +#LIB2ADD = $(LIB2FUNCS_EXTRA) +#LIB2ADD_ST = $(LIB2FUNCS_STATIC_EXTRA) +LIB2ADD = +LIB2ADD_ST = libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) $(LIB2ADD_ST) xgcc$(exeext) specs objext='$(objext)' \ From brukman at cs.uiuc.edu Mon Aug 9 13:37:14 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 13:37:14 -0500 Subject: [llvm-commits] CVS: llvm/docs/CFEBuildInstrs.html Message-ID: <200408091837.NAA17560@zion.cs.uiuc.edu> Changes in directory llvm/docs: CFEBuildInstrs.html updated: 1.21 -> 1.22 --- Log message: * CFE builds on AIX/PowerPC * Wrap long code lines --- Diffs of the changes: (+7 -6) Index: llvm/docs/CFEBuildInstrs.html diff -u llvm/docs/CFEBuildInstrs.html:1.21 llvm/docs/CFEBuildInstrs.html:1.22 --- llvm/docs/CFEBuildInstrs.html:1.21 Mon Jul 19 13:47:59 2004 +++ llvm/docs/CFEBuildInstrs.html Mon Aug 9 13:37:04 2004 @@ -109,13 +109,14 @@

Linux/x86:
-MacOS X/PowerPC (requires dlcompat library): +MacOS X/PowerPC (requires dlcompat library):
+AIX/PowerPC:

  % cd build
- % ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls --disable-shared \
-   --enable-languages=c,c++
+ % ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls \
+   --disable-shared --enable-languages=c,c++
  % gmake
  % setenv LLVM_LIB_SEARCH_PATH `pwd`/gcc 
  % gmake all; gmake install
@@ -125,8 +126,8 @@
 
 
  % cd build
- % ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls --disable-shared \
-   --enable-languages=c,c++ --disable-c-mbchar
+ % ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls \
+   --disable-shared --enable-languages=c,c++ --disable-c-mbchar
  % gmake
  % setenv LLVM_LIB_SEARCH_PATH `pwd`/gcc 
  % gmake all; gmake install
@@ -302,7 +303,7 @@
 
   Brian Gaeke
LLVM Compiler Infrastructure
- Last modified: $Date: 2004/07/19 18:47:59 $ + Last modified: $Date: 2004/08/09 18:37:04 $ From sabre at nondot.org Mon Aug 9 13:59:18 2004 From: sabre at nondot.org (Chris Lattner) Date: Mon, 9 Aug 2004 13:59:18 -0500 (CDT) Subject: [llvm-commits] test Message-ID: is the mailing list blocked? -Chris -- http://llvm.cs.uiuc.edu/ http://nondot.org/sabre/ From criswell at cs.uiuc.edu Mon Aug 9 14:08:09 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Mon, 9 Aug 2004 14:08:09 -0500 Subject: [llvm-commits] [release_13] CVS: llvm-gcc/gcc/Makefile.in Message-ID: <200408091908.OAA25765@zion.cs.uiuc.edu> Changes in directory llvm-gcc/gcc: Makefile.in updated: 1.3 -> 1.3.4.1 --- Log message: Merged changes from HEAD on August 9, 2004, 2:07 pm CST. --- Diffs of the changes: (+8 -2) Index: llvm-gcc/gcc/Makefile.in diff -u llvm-gcc/gcc/Makefile.in:1.3 llvm-gcc/gcc/Makefile.in:1.3.4.1 --- llvm-gcc/gcc/Makefile.in:1.3 Thu Feb 5 10:05:44 2004 +++ llvm-gcc/gcc/Makefile.in Mon Aug 9 14:07:57 2004 @@ -1113,8 +1113,14 @@ # # Build libgcc.a. -LIB2ADD = $(LIB2FUNCS_EXTRA) -LIB2ADD_ST = $(LIB2FUNCS_STATIC_EXTRA) +### +### For LLVM GCC, we do not want to add any target-specific .s files or other +### gunk to libgcc. +### +#LIB2ADD = $(LIB2FUNCS_EXTRA) +#LIB2ADD_ST = $(LIB2FUNCS_STATIC_EXTRA) +LIB2ADD = +LIB2ADD_ST = libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) $(LIB2ADD_ST) xgcc$(exeext) specs objext='$(objext)' \ From brukman at cs.uiuc.edu Mon Aug 9 14:10:53 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 14:10:53 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/CodeEmitterGen.cpp Message-ID: <200408091910.OAA08188@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: CodeEmitterGen.cpp updated: 1.32 -> 1.33 --- Log message: Use the current target name instead of a ClassPrefix. --- Diffs of the changes: (+3 -3) Index: llvm/utils/TableGen/CodeEmitterGen.cpp diff -u llvm/utils/TableGen/CodeEmitterGen.cpp:1.32 llvm/utils/TableGen/CodeEmitterGen.cpp:1.33 --- llvm/utils/TableGen/CodeEmitterGen.cpp:1.32 Mon Aug 9 12:47:45 2004 +++ llvm/utils/TableGen/CodeEmitterGen.cpp Mon Aug 9 14:10:43 2004 @@ -14,21 +14,21 @@ //===----------------------------------------------------------------------===// #include "CodeEmitterGen.h" +#include "CodeGenTarget.h" #include "Record.h" #include "Support/Debug.h" using namespace llvm; void CodeEmitterGen::run(std::ostream &o) { + CodeGenTarget Target; std::vector Insts = Records.getAllDerivedDefinitions("Instruction"); EmitSourceFileHeader("Machine Code Emitter", o); std::string Namespace = Insts[0]->getValueAsString("Namespace") + "::"; - std::string ClassName = Insts[0]->getValueAsString("ClassPrefix") + - "CodeEmitter::"; //const std::string &Namespace = Inst->getValue("Namespace")->getName(); - o << "unsigned " << ClassName + o << "unsigned " << Target.getName() << "CodeEmitter::" << "getBinaryCodeForInstr(MachineInstr &MI) {\n" << " unsigned Value = 0;\n" << " DEBUG(std::cerr << MI);\n" From brukman at cs.uiuc.edu Mon Aug 9 14:13:32 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 14:13:32 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/Target.td Message-ID: <200408091913.OAA16708@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target: Target.td updated: 1.30 -> 1.31 --- Log message: Remove ClassPrefix variable as it's no longer used. --- Diffs of the changes: (+0 -1) Index: llvm/lib/Target/Target.td diff -u llvm/lib/Target/Target.td:1.30 llvm/lib/Target/Target.td:1.31 --- llvm/lib/Target/Target.td:1.30 Mon Aug 9 12:46:06 2004 +++ llvm/lib/Target/Target.td Mon Aug 9 14:13:22 2004 @@ -108,7 +108,6 @@ class Instruction { string Name = ""; // The opcode string for this instruction string Namespace = ""; - string ClassPrefix = ""; dag OperandList; // An dag containing the MI operand list. string AsmString = ""; // The .s format to print the instruction with. From brukman at cs.uiuc.edu Mon Aug 9 14:13:35 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 14:13:35 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Message-ID: <200408091913.OAA16714@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCInstrFormats.td updated: 1.5 -> 1.6 --- Log message: Remove ClassPrefix variable as it's no longer used. --- Diffs of the changes: (+0 -1) Index: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.5 llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.6 --- llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.5 Mon Aug 9 12:46:26 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Mon Aug 9 14:13:25 2004 @@ -56,7 +56,6 @@ let Name = name; let Namespace = "PPC32"; - let ClassPrefix = "PowerPC"; let Inst{0-5} = opcode; } From brukman at cs.uiuc.edu Mon Aug 9 14:13:37 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 14:13:37 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9.td Message-ID: <200408091913.OAA16720@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9.td updated: 1.34 -> 1.35 --- Log message: Remove ClassPrefix variable as it's no longer used. --- Diffs of the changes: (+0 -1) Index: llvm/lib/Target/SparcV9/SparcV9.td diff -u llvm/lib/Target/SparcV9/SparcV9.td:1.34 llvm/lib/Target/SparcV9/SparcV9.td:1.35 --- llvm/lib/Target/SparcV9/SparcV9.td:1.34 Mon Aug 9 12:46:49 2004 +++ llvm/lib/Target/SparcV9/SparcV9.td Mon Aug 9 14:13:27 2004 @@ -24,7 +24,6 @@ field bits<32> Inst; let Namespace = "V9"; - let ClassPrefix = "SparcV9"; bits<2> op; let Inst{31-30} = op; // Top two bits are the 'op' field From brukman at cs.uiuc.edu Mon Aug 9 14:38:51 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 14:38:51 -0500 Subject: [llvm-commits] CVS: llvm-gcc/gcc/llvm-macros.h varasm.c Message-ID: <200408091938.OAA07647@zion.cs.uiuc.edu> Changes in directory llvm-gcc/gcc: llvm-macros.h added (r1.1) varasm.c updated: 1.4 -> 1.5 --- Log message: If ASM_OUTPUT_DEF is *still* not defined due to ifdef/ifndef madness, make it default to nothing to avoid missing a definition. Fixes compilation on AIX. --- Diffs of the changes: (+16 -0) Index: llvm-gcc/gcc/llvm-macros.h diff -c /dev/null llvm-gcc/gcc/llvm-macros.h:1.1 *** /dev/null Mon Aug 9 14:38:50 2004 --- llvm-gcc/gcc/llvm-macros.h Mon Aug 9 14:38:40 2004 *************** *** 0 **** --- 1,15 ---- + /* + * The GCC #ifdef soup prevents some #defines to be actually #defined. + * Since we don't really use assembly emission from GCC, we can #define the + * missing macros to empty, so we do it here to avoid polluting GCC headers, + * to make it easier to sync up to CVs. + */ + + #ifndef LLVM_MACROS_H + #define LLVM_MACROS_H + + #ifndef ASM_OUTPUT_DEF + #define ASM_OUTPUT_DEF(a,b,c) + #endif + + #endif Index: llvm-gcc/gcc/varasm.c diff -u llvm-gcc/gcc/varasm.c:1.4 llvm-gcc/gcc/varasm.c:1.5 --- llvm-gcc/gcc/varasm.c:1.4 Tue Jun 8 02:34:54 2004 +++ llvm-gcc/gcc/varasm.c Mon Aug 9 14:38:40 2004 @@ -51,6 +51,7 @@ #include "cgraph.h" #include "llvm-out.h" +#include "llvm-macros.h" #ifdef XCOFF_DEBUGGING_INFO #include "xcoffout.h" /* Needed for external data From brukman at cs.uiuc.edu Mon Aug 9 14:52:00 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 14:52:00 -0500 Subject: [llvm-commits] CVS: llvm/runtime/GCCLibraries/Makefile Message-ID: <200408091952.OAA07856@zion.cs.uiuc.edu> Changes in directory llvm/runtime/GCCLibraries: Makefile updated: 1.5 -> 1.6 --- Log message: Remove Chris-related bytecode-dir comment --- Diffs of the changes: (+4 -5) Index: llvm/runtime/GCCLibraries/Makefile diff -u llvm/runtime/GCCLibraries/Makefile:1.5 llvm/runtime/GCCLibraries/Makefile:1.6 --- llvm/runtime/GCCLibraries/Makefile:1.5 Mon Dec 8 14:12:46 2003 +++ llvm/runtime/GCCLibraries/Makefile Mon Aug 9 14:51:49 2004 @@ -1,4 +1,4 @@ -##===- runtime/GCCLibraries/Makefile ------------------------------*- Makefile -*-===## +##===- runtime/GCCLibraries/Makefile -----------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -6,14 +6,13 @@ # the University of Illinois Open Source License. See LICENSE.TXT for details. # ##===----------------------------------------------------------------------===## -# llvm/runtime/GCCLibraries Makefile: Build all subdirectories automatically LEVEL = ../.. -PARALLEL_DIRS := crtend libc libcurses libg libgcc libgdbm libm libmalloc libtermcap libucb libutempter libutil +PARALLEL_DIRS := crtend libc libcurses libg libgcc libgdbm libm libmalloc \ + libtermcap libucb libutempter libutil include $(LEVEL)/Makefile.common -# Install target for libraries: Copy into the gcc install directory in chris's -# tree... +# Install target for libraries: copy bytecode files to $LLVMGCCDIR/bytecode-libs # install:: From brukman at cs.uiuc.edu Mon Aug 9 14:57:11 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 14:57:11 -0500 Subject: [llvm-commits] CVS: llvm/docs/GettingStarted.html Message-ID: <200408091957.OAA08023@zion.cs.uiuc.edu> Changes in directory llvm/docs: GettingStarted.html updated: 1.64 -> 1.65 --- Log message: Add note about AIX/PowerPC with disk space requirements. Wrap long line. --- Diffs of the changes: (+17 -5) Index: llvm/docs/GettingStarted.html diff -u llvm/docs/GettingStarted.html:1.64 llvm/docs/GettingStarted.html:1.65 --- llvm/docs/GettingStarted.html:1.64 Tue Jul 20 15:25:18 2004 +++ llvm/docs/GettingStarted.html Mon Aug 9 14:57:01 2004 @@ -202,7 +202,7 @@
  • Approximately 1.75 GB of Free Disk Space
    • Source code: 45 MB
    • -
    • Object code: 1705 MB
    • +
    • Object code: 1.7 GB
    • GCC front end: 50 MB
  • @@ -221,16 +221,27 @@
  • MacOS X on PowerPC
      -
    • No native code generation
    • Approximately 1.25 GB of Free Disk Space
      • Source code: 45 MB
      • -
      • Object code: 1160 MB
      • +
      • Object code: 1.2 GB
      • GCC front end: 40 MB
    +
  • +
  • AIX on PowerPC +
      +
    • No native code generation
      +
    • Approximately 2 GB of Free Disk Space +
        +
      • Source code: 92 MB
      • +
      • Object code: 2.8 GB
      • +
      • GCC front end: 123 MB
      • +
    • +
  • +

    The LLVM suite may compile on other platforms, but it is not @@ -240,7 +251,8 @@ on your platform.

    The GCC front end is not very portable at the moment. If you want to get it -to work on another platform, you can download a copy of the source and try to compile it on your platform.

    +to work on another platform, you can download a copy of the source and try to compile it on your platform.

    @@ -1266,7 +1278,7 @@ Chris Lattner
    The LLVM Compiler Infrastructure
    - Last modified: $Date: 2004/07/20 20:25:18 $ + Last modified: $Date: 2004/08/09 19:57:01 $ From brukman at cs.uiuc.edu Mon Aug 9 15:07:54 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 15:07:54 -0500 Subject: [llvm-commits] CVS: llvm/runtime/Makefile Message-ID: <200408092007.PAA08221@zion.cs.uiuc.edu> Changes in directory llvm/runtime: Makefile updated: 1.18 -> 1.19 --- Log message: * Remove UIUC-specific comment * Make header comment span 80 cols --- Diffs of the changes: (+2 -4) Index: llvm/runtime/Makefile diff -u llvm/runtime/Makefile:1.18 llvm/runtime/Makefile:1.19 --- llvm/runtime/Makefile:1.18 Sun May 23 16:26:29 2004 +++ llvm/runtime/Makefile Mon Aug 9 15:07:44 2004 @@ -1,4 +1,4 @@ -##===- runtime/Makefile ------------------------------*- Makefile -*-===## +##===- runtime/Makefile ------------------------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -6,7 +6,6 @@ # the University of Illinois Open Source License. See LICENSE.TXT for details. # ##===----------------------------------------------------------------------===## -# llvm/runtime Makefile: Build all subdirectories automatically LEVEL = .. include $(LEVEL)/Makefile.config @@ -24,8 +23,7 @@ include $(LEVEL)/Makefile.common -# Install target for libraries: Copy into the 'bytecode-libs' subdirectory -# of LLVMGCCDIR. (On the UIUC machines, this is in Chris's home directory.) +# Install target for libraries: Copy into $LLVMGCCDIR/bytecode-libs # install:: From brukman at cs.uiuc.edu Mon Aug 9 15:13:24 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 15:13:24 -0500 Subject: [llvm-commits] CVS: llvm/runtime/GCCLibraries/libucb/Makefile Message-ID: <200408092013.PAA08371@zion.cs.uiuc.edu> Changes in directory llvm/runtime/GCCLibraries/libucb: Makefile updated: 1.3 -> 1.4 --- Log message: Shorten comment header to 80 cols --- Diffs of the changes: (+1 -1) Index: llvm/runtime/GCCLibraries/libucb/Makefile diff -u llvm/runtime/GCCLibraries/libucb/Makefile:1.3 llvm/runtime/GCCLibraries/libucb/Makefile:1.4 --- llvm/runtime/GCCLibraries/libucb/Makefile:1.3 Mon Oct 20 17:28:48 2003 +++ llvm/runtime/GCCLibraries/libucb/Makefile Mon Aug 9 15:13:14 2004 @@ -1,4 +1,4 @@ -##===- runtime/GCCLibraries/libucb/Makefile ------------------------------*- Makefile -*-===## +##===- runtime/GCCLibraries/libucb/Makefile ----------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # From brukman at cs.uiuc.edu Mon Aug 9 15:13:25 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 15:13:25 -0500 Subject: [llvm-commits] CVS: llvm/runtime/GCCLibraries/libutempter/Makefile Message-ID: <200408092013.PAA08374@zion.cs.uiuc.edu> Changes in directory llvm/runtime/GCCLibraries/libutempter: Makefile updated: 1.2 -> 1.3 --- Log message: Shorten comment header to 80 cols --- Diffs of the changes: (+1 -1) Index: llvm/runtime/GCCLibraries/libutempter/Makefile diff -u llvm/runtime/GCCLibraries/libutempter/Makefile:1.2 llvm/runtime/GCCLibraries/libutempter/Makefile:1.3 --- llvm/runtime/GCCLibraries/libutempter/Makefile:1.2 Mon Oct 20 17:28:48 2003 +++ llvm/runtime/GCCLibraries/libutempter/Makefile Mon Aug 9 15:13:14 2004 @@ -1,4 +1,4 @@ -##===- runtime/GCCLibraries/libutempter/Makefile ------------------------------*- Makefile -*-===## +##===- runtime/GCCLibraries/libutempter/Makefile -----------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # From brukman at cs.uiuc.edu Mon Aug 9 15:13:25 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 15:13:25 -0500 Subject: [llvm-commits] CVS: llvm/runtime/GCCLibraries/libg/Makefile Message-ID: <200408092013.PAA08377@zion.cs.uiuc.edu> Changes in directory llvm/runtime/GCCLibraries/libg: Makefile updated: 1.3 -> 1.4 --- Log message: Shorten comment header to 80 cols --- Diffs of the changes: (+1 -1) Index: llvm/runtime/GCCLibraries/libg/Makefile diff -u llvm/runtime/GCCLibraries/libg/Makefile:1.3 llvm/runtime/GCCLibraries/libg/Makefile:1.4 --- llvm/runtime/GCCLibraries/libg/Makefile:1.3 Mon Oct 20 17:28:48 2003 +++ llvm/runtime/GCCLibraries/libg/Makefile Mon Aug 9 15:13:14 2004 @@ -1,4 +1,4 @@ -##===- runtime/GCCLibraries/libg/Makefile ------------------------------*- Makefile -*-===## +##===- runtime/GCCLibraries/libg/Makefile ------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # From brukman at cs.uiuc.edu Mon Aug 9 15:13:25 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 15:13:25 -0500 Subject: [llvm-commits] CVS: llvm/runtime/GCCLibraries/libgcc/Makefile Message-ID: <200408092013.PAA08380@zion.cs.uiuc.edu> Changes in directory llvm/runtime/GCCLibraries/libgcc: Makefile updated: 1.3 -> 1.4 --- Log message: Shorten comment header to 80 cols --- Diffs of the changes: (+1 -1) Index: llvm/runtime/GCCLibraries/libgcc/Makefile diff -u llvm/runtime/GCCLibraries/libgcc/Makefile:1.3 llvm/runtime/GCCLibraries/libgcc/Makefile:1.4 --- llvm/runtime/GCCLibraries/libgcc/Makefile:1.3 Mon Oct 20 17:28:48 2003 +++ llvm/runtime/GCCLibraries/libgcc/Makefile Mon Aug 9 15:13:14 2004 @@ -1,4 +1,4 @@ -##===- runtime/GCCLibraries/libgcc/Makefile ------------------------------*- Makefile -*-===## +##===- runtime/GCCLibraries/libgcc/Makefile ----------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # From brukman at cs.uiuc.edu Mon Aug 9 15:23:55 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 15:23:55 -0500 Subject: [llvm-commits] CVS: llvm/runtime/GC/Makefile Message-ID: <200408092023.PAA08508@zion.cs.uiuc.edu> Changes in directory llvm/runtime/GC: Makefile updated: 1.1 -> 1.2 --- Log message: Do not mention Chris in public Makefiles --- Diffs of the changes: (+1 -3) Index: llvm/runtime/GC/Makefile diff -u llvm/runtime/GC/Makefile:1.1 llvm/runtime/GC/Makefile:1.2 --- llvm/runtime/GC/Makefile:1.1 Sun May 23 16:25:59 2004 +++ llvm/runtime/GC/Makefile Mon Aug 9 15:23:44 2004 @@ -9,11 +9,9 @@ LEVEL = ../.. PARALLEL_DIRS := SemiSpace - include $(LEVEL)/Makefile.common -# Install target for libraries: Copy into the gcc install directory in chris's -# tree... +# Install target for libraries: Copy into $LLVMGCCDIR/bytecode-libs # install:: From lattner at cs.uiuc.edu Mon Aug 9 16:03:45 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 9 Aug 2004 16:03:45 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/InstCombine/2004-08-09-RemInfLoop.llx Message-ID: <200408092103.QAA08819@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/InstCombine: 2004-08-09-RemInfLoop.llx added (r1.1) --- Log message: New testcase --- Diffs of the changes: (+8 -0) Index: llvm/test/Regression/Transforms/InstCombine/2004-08-09-RemInfLoop.llx diff -c /dev/null llvm/test/Regression/Transforms/InstCombine/2004-08-09-RemInfLoop.llx:1.1 *** /dev/null Mon Aug 9 16:03:45 2004 --- llvm/test/Regression/Transforms/InstCombine/2004-08-09-RemInfLoop.llx Mon Aug 9 16:03:35 2004 *************** *** 0 **** --- 1,8 ---- + ; RUN: llvm-as < %s | opt -instcombine + + ; This testcase should not send the instcombiner into an infinite loop! + + int %test(int %X) { + %Y = rem int %X, 0 + ret int %Y + } From lattner at cs.uiuc.edu Mon Aug 9 16:05:58 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 9 Aug 2004 16:05:58 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Scalar/InstructionCombining.cpp Message-ID: <200408092105.QAA09327@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Scalar: InstructionCombining.cpp updated: 1.237 -> 1.238 --- Log message: Fix InstCombine/2004-08-09-RemInfLoop.llx This should go into the 1.3 branch --- Diffs of the changes: (+1 -1) Index: llvm/lib/Transforms/Scalar/InstructionCombining.cpp diff -u llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.237 llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.238 --- llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.237 Wed Aug 4 03:24:25 2004 +++ llvm/lib/Transforms/Scalar/InstructionCombining.cpp Mon Aug 9 16:05:48 2004 @@ -829,7 +829,7 @@ if (I.getType()->isSigned()) if (Value *RHSNeg = dyn_castNegVal(I.getOperand(1))) if (!isa(RHSNeg) || - cast(RHSNeg)->getValue() >= 0) { + cast(RHSNeg)->getValue() > 0) { // X % -Y -> X % Y AddUsesToWorkList(I); I.setOperand(1, RHSNeg); From criswell at cs.uiuc.edu Mon Aug 9 16:15:30 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Mon, 9 Aug 2004 16:15:30 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/docs/ReleaseNotes.html Message-ID: <200408092115.QAA11076@zion.cs.uiuc.edu> Changes in directory llvm/docs: ReleaseNotes.html updated: 1.225 -> 1.225.2.1 --- Log message: Updated release notes from mainline. --- Diffs of the changes: (+20 -15) Index: llvm/docs/ReleaseNotes.html diff -u llvm/docs/ReleaseNotes.html:1.225 llvm/docs/ReleaseNotes.html:1.225.2.1 --- llvm/docs/ReleaseNotes.html:1.225 Wed Aug 4 03:00:45 2004 +++ llvm/docs/ReleaseNotes.html Mon Aug 9 16:15:20 2004 @@ -73,7 +73,8 @@ release primarily improves the performance of the code produced by all aspects of the LLVM compiler, adds many new features, fixes a few -bugs, and speeds up the compiler.

    +bugs, speeds up the compiler, and introduces a new (experimental) +PowerPC code generator.

    At this time, LLVM is known to correctly compile and run all C & C++ SPEC CPU95 & 2000 benchmarks, the Olden benchmarks, and the Ptrdist @@ -149,6 +150,8 @@

  • All LLVM tools will now respond to the --version option which will tell you the version of LLVM on which the tool is based.
  • +
  • An experimental PowerPC backend has been added, capable of compiling several +SPEC benchmarks.
  • @@ -198,13 +201,15 @@ Bytecode Reader
  • Global Vars Have (Somewhat) Limited Type Range
  • -
  • operator<< on a Value* now prints the address of the object instead of its contents.
  • +
  • operator<< on a Value* now +prints the address of the object instead of its contents.
  • Bytecode Enhancements - Needed
  • -
  • [loopsimplify] Loop simplify is really slow on 252.eon
  • -
  • [code-cleanup] SymbolTable - class cleanup, Type should not derive from Value, eliminate - ConstantPointerRef class.
  • +Needed +
  • [loopsimplify] Loop simplify is +really slow on 252.eon
  • +
  • [code-cleanup] SymbolTable class +cleanup, Type should not derive from Value, eliminate ConstantPointerRef +class.
  • The memory footprint of the LLVM IR has been reduced substantially.
  • The LLVM linker and many core classes have been sped up substantially.
  • @@ -345,12 +350,12 @@
  • Intel and AMD machines running Red Hat Linux and FreeBSD (and probably other unix-like systems).
  • Sun UltraSPARC workstations running Solaris 8.
  • -
  • PowerPC-based Mac OS X boxes, running 10.3 and above (C backend and - interpreter only, no native codegen is available yet).
  • Intel and AMD machines running on Win32 with the Cygwin libraries.
  • +
  • PowerPC-based Mac OS X boxes, running 10.2 and above. Note that no JIT +support is available yet, and LLC support is beta. The C backend can be used +to produce stable code for this platform.
  • -

    The core LLVM infrastructure uses GNU autoconf to adapt itself to the machine and operating system on which it is built. However, minor @@ -396,9 +401,11 @@ components, please contact us on the llvmdev list.

      +
    • The PowerPC backend is incomplete and is known to miscompile several SPEC +benchmarks. The file llvm/lib/Target/PowerPC/README.txt has +details.
    • The following passes are incomplete or buggy: -pgmdep, -memdep, -ipmodref, -cee
    • -
    • The -pre pass is incomplete (there are cases it doesn't handle that it should) and not thoroughly tested.
    • The llvm-ar tool is incomplete and probably buggy.
    • @@ -423,9 +430,7 @@ such, execution of a threaded program could cause these data structures to be corrupted. -
    • It is not possible to dlopen an LLVM bytecode file in the JIT.
    • - -
    • Linking in static archive files (.a files) is very slow (there is no symbol +
    • Linking in static archive files (.a files) is slow (there is no symbol table in the archive).
    • The gccld program does not link @@ -761,7 +766,7 @@ src="http://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01!" /> The LLVM Compiler Infrastructure
      - Last modified: $Date: 2004/08/04 08:00:45 $ + Last modified: $Date: 2004/08/09 21:15:20 $ From lattner at cs.uiuc.edu Mon Aug 9 16:17:07 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 9 Aug 2004 16:17:07 -0500 Subject: [llvm-commits] CVS: llvm-www/demo/index.cgi Message-ID: <200408092117.QAA11176@zion.cs.uiuc.edu> Changes in directory llvm-www/demo: index.cgi updated: 1.26 -> 1.27 --- Log message: Hack to hopefully fix demo page on zion --- Diffs of the changes: (+2 -2) Index: llvm-www/demo/index.cgi diff -u llvm-www/demo/index.cgi:1.26 llvm-www/demo/index.cgi:1.27 --- llvm-www/demo/index.cgi:1.26 Thu Jul 8 22:24:32 2004 +++ llvm-www/demo/index.cgi Mon Aug 9 16:16:56 2004 @@ -5,7 +5,7 @@ # doing remote web JO99C compilations. (It could still be used for that # purpose, though the two scripts have diverged somewhat.) # -# Last modified $Date: 2004/07/09 03:24:32 $ +# Last modified $Date: 2004/08/09 21:16:56 $ # use CGI; @@ -26,7 +26,7 @@ ( '/home/vadve/gaeke/llvm/tools/Debug', '/home/vadve/gaeke/bin' ); $ENV{'LLVM_LIB_SEARCH_PATH'} = '/home/vadve/lattner/local/x86/llvm-gcc/bytecode-libs'; -$ENV{'LD_LIBRARY_PATH'} = '/home/vadve/shared/localtools/x86/lib'; +$ENV{'LD_LIBRARY_PATH'} = '/home/vadve/shared/localtools/fc1/lib/'; sub getname { my ($extension) = @_; From criswell at cs.uiuc.edu Mon Aug 9 16:17:27 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Mon, 9 Aug 2004 16:17:27 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/docs/ReleaseNotes.html Message-ID: <200408092117.QAA11225@zion.cs.uiuc.edu> Changes in directory llvm/docs: ReleaseNotes.html updated: 1.225.2.1 -> 1.225.2.2 --- Log message: Fix capitalization of URL. --- Diffs of the changes: (+2 -2) Index: llvm/docs/ReleaseNotes.html diff -u llvm/docs/ReleaseNotes.html:1.225.2.1 llvm/docs/ReleaseNotes.html:1.225.2.2 --- llvm/docs/ReleaseNotes.html:1.225.2.1 Mon Aug 9 16:15:20 2004 +++ llvm/docs/ReleaseNotes.html Mon Aug 9 16:17:16 2004 @@ -207,7 +207,7 @@ Needed
    • [loopsimplify] Loop simplify is really slow on 252.eon
    • -
    • [code-cleanup] SymbolTable class +
    • [code-cleanup] SymbolTable class cleanup, Type should not derive from Value, eliminate ConstantPointerRef class.
    • The memory footprint of the LLVM IR has been reduced substantially.
    • @@ -766,7 +766,7 @@ src="http://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01!" /> The LLVM Compiler Infrastructure
      - Last modified: $Date: 2004/08/09 21:15:20 $ + Last modified: $Date: 2004/08/09 21:17:16 $ From criswell at cs.uiuc.edu Mon Aug 9 16:34:03 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Mon, 9 Aug 2004 16:34:03 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/test/Regression/Transforms/InstCombine/2004-08-09-RemInfLoop.llx Message-ID: <200408092134.QAA22595@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/InstCombine: 2004-08-09-RemInfLoop.llx added (r1.1.2.1) --- Log message: Merged in new regression test. --- Diffs of the changes: (+8 -0) Index: llvm/test/Regression/Transforms/InstCombine/2004-08-09-RemInfLoop.llx diff -c /dev/null llvm/test/Regression/Transforms/InstCombine/2004-08-09-RemInfLoop.llx:1.1.2.1 *** /dev/null Mon Aug 9 16:34:03 2004 --- llvm/test/Regression/Transforms/InstCombine/2004-08-09-RemInfLoop.llx Mon Aug 9 16:33:52 2004 *************** *** 0 **** --- 1,8 ---- + ; RUN: llvm-as < %s | opt -instcombine + + ; This testcase should not send the instcombiner into an infinite loop! + + int %test(int %X) { + %Y = rem int %X, 0 + ret int %Y + } From criswell at cs.uiuc.edu Mon Aug 9 16:34:44 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Mon, 9 Aug 2004 16:34:44 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/lib/Transforms/Scalar/InstructionCombining.cpp Message-ID: <200408092134.QAA24371@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Scalar: InstructionCombining.cpp updated: 1.237 -> 1.237.2.1 --- Log message: Merged in changes to the instruction combining pass. --- Diffs of the changes: (+1 -1) Index: llvm/lib/Transforms/Scalar/InstructionCombining.cpp diff -u llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.237 llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.237.2.1 --- llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.237 Wed Aug 4 03:24:25 2004 +++ llvm/lib/Transforms/Scalar/InstructionCombining.cpp Mon Aug 9 16:34:34 2004 @@ -829,7 +829,7 @@ if (I.getType()->isSigned()) if (Value *RHSNeg = dyn_castNegVal(I.getOperand(1))) if (!isa(RHSNeg) || - cast(RHSNeg)->getValue() >= 0) { + cast(RHSNeg)->getValue() > 0) { // X % -Y -> X % Y AddUsesToWorkList(I); I.setOperand(1, RHSNeg); From brukman at cs.uiuc.edu Mon Aug 9 17:27:55 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 17:27:55 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPC.h PowerPCAsmPrinter.cpp PowerPCTargetMachine.cpp Message-ID: <200408092227.RAA25289@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPC.h updated: 1.3 -> 1.4 PowerPCAsmPrinter.cpp updated: 1.31 -> 1.32 PowerPCTargetMachine.cpp updated: 1.22 -> 1.23 --- Log message: CodePrinter -> AsmPrinter --- Diffs of the changes: (+5 -5) Index: llvm/lib/Target/PowerPC/PowerPC.h diff -u llvm/lib/Target/PowerPC/PowerPC.h:1.3 llvm/lib/Target/PowerPC/PowerPC.h:1.4 --- llvm/lib/Target/PowerPC/PowerPC.h:1.3 Fri Aug 6 01:58:50 2004 +++ llvm/lib/Target/PowerPC/PowerPC.h Mon Aug 9 17:27:45 2004 @@ -25,7 +25,7 @@ // Here is where you would define factory methods for powerpc-specific // passes. For example: FunctionPass *createPPCSimpleInstructionSelector(TargetMachine &TM); -FunctionPass *createPPCCodePrinterPass(std::ostream &OS, TargetMachine &TM); +FunctionPass *createPPCAsmPrinterPass(std::ostream &OS, TargetMachine &TM); FunctionPass *createPowerPCPEI(); FunctionPass *createPPCBranchSelectionPass(); } // end namespace llvm; Index: llvm/lib/Target/PowerPC/PowerPCAsmPrinter.cpp diff -u llvm/lib/Target/PowerPC/PowerPCAsmPrinter.cpp:1.31 llvm/lib/Target/PowerPC/PowerPCAsmPrinter.cpp:1.32 --- llvm/lib/Target/PowerPC/PowerPCAsmPrinter.cpp:1.31 Wed Aug 4 12:29:14 2004 +++ llvm/lib/Target/PowerPC/PowerPCAsmPrinter.cpp Mon Aug 9 17:27:45 2004 @@ -85,12 +85,12 @@ }; } // end of anonymous namespace -/// createPPCCodePrinterPass - Returns a pass that prints the PPC +/// createPPCAsmPrinterPass - Returns a pass that prints the PPC /// assembly code for a MachineFunction to the given output stream, /// using the given target machine description. This should work -/// regardless of whether the function is in SSA form. +/// regardless of whether the function is in SSA form or not. /// -FunctionPass *createPPCCodePrinterPass(std::ostream &o,TargetMachine &tm) { +FunctionPass *createPPCAsmPrinterPass(std::ostream &o,TargetMachine &tm) { return new Printer(o, tm); } Index: llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp diff -u llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.22 llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.23 --- llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.22 Fri Aug 6 01:58:50 2004 +++ llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp Mon Aug 9 17:27:45 2004 @@ -91,7 +91,7 @@ // Must run branch selection immediately preceding the printer PM.add(createPPCBranchSelectionPass()); - PM.add(createPPCCodePrinterPass(Out, *this)); + PM.add(createPPCAsmPrinterPass(Out, *this)); PM.add(createMachineCodeDeleter()); return false; } From brukman at cs.uiuc.edu Mon Aug 9 18:04:10 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Mon, 9 Aug 2004 18:04:10 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCCodeEmitter.cpp Message-ID: <200408092304.SAA27397@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCCodeEmitter.cpp updated: 1.1.1.1 -> 1.2 --- Log message: Stub definition of the PowerPC CodeEmitter class; this isn't functional (yet). --- Diffs of the changes: (+61 -4) Index: llvm/lib/Target/PowerPC/PowerPCCodeEmitter.cpp diff -u llvm/lib/Target/PowerPC/PowerPCCodeEmitter.cpp:1.1.1.1 llvm/lib/Target/PowerPC/PowerPCCodeEmitter.cpp:1.2 --- llvm/lib/Target/PowerPC/PowerPCCodeEmitter.cpp:1.1.1.1 Mon Jun 21 11:55:26 2004 +++ llvm/lib/Target/PowerPC/PowerPCCodeEmitter.cpp Mon Aug 9 18:03:59 2004 @@ -11,9 +11,44 @@ //===----------------------------------------------------------------------===// #include "PowerPCTargetMachine.h" +#include "llvm/CodeGen/MachineCodeEmitter.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/Passes.h" +#include "Support/Debug.h" namespace llvm { +namespace { + class PowerPCCodeEmitter : public MachineFunctionPass { + TargetMachine &TM; + MachineCodeEmitter &MCE; + + public: + PowerPCCodeEmitter(TargetMachine &T, MachineCodeEmitter &M) + : TM(T), MCE(M) {} + + const char *getPassName() const { return "PowerPC Machine Code Emitter"; } + + /// runOnMachineFunction - emits the given MachineFunction to memory + /// + bool runOnMachineFunction(MachineFunction &MF); + + /// emitBasicBlock - emits the given MachineBasicBlock to memory + /// + void emitBasicBlock(MachineBasicBlock &MBB); + + /// emitWord - write a 32-bit word to memory at the current PC + /// + void emitWord(unsigned w) { MCE.emitWord(w); } + + unsigned getValueBit(int64_t Val, unsigned bit); + + /// getBinaryCodeForInstr - returns the assembled code for an instruction + /// + unsigned getBinaryCodeForInstr(MachineInstr &MI) { return 0; } + }; +} + /// 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 @@ -22,11 +57,31 @@ /// 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 + // Machine code emitter pass for PowerPC + PM.add(new PowerPCCodeEmitter(*this, MCE)); // Delete machine code for this function after emitting it: - // PM.add(createMachineCodeDeleter()); + PM.add(createMachineCodeDeleter()); + // We don't yet support machine code emission + return true; +} + +bool PowerPCCodeEmitter::runOnMachineFunction(MachineFunction &MF) { + MCE.startFunction(MF); + MCE.emitConstantPool(MF.getConstantPool()); + for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) + emitBasicBlock(*I); + MCE.finishFunction(MF); + return false; +} + +void PowerPCCodeEmitter::emitBasicBlock(MachineBasicBlock &MBB) { + for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I) + emitWord(getBinaryCodeForInstr(*I)); +} + +unsigned PowerPCCodeEmitter::getValueBit(int64_t Val, unsigned bit) { + Val >>= bit; + return (Val & 1); } void *PowerPCJITInfo::getJITStubForFunction(Function *F, @@ -39,5 +94,7 @@ assert (0 && "PowerPCJITInfo::replaceMachineCodeForFunction not implemented"); } +//#include "PowerPCGenCodeEmitter.inc" + } // end llvm namespace From lattner at cs.uiuc.edu Mon Aug 9 18:56:27 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 9 Aug 2004 18:56:27 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/CodeGen/CBackend/2004-08-09-va-end-null.ll Message-ID: <200408092356.SAA30190@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/CodeGen/CBackend: 2004-08-09-va-end-null.ll added (r1.1) --- Log message: This testcase causes the CBE to generate code that is not legal C. --- Diffs of the changes: (+7 -0) Index: llvm/test/Regression/CodeGen/CBackend/2004-08-09-va-end-null.ll diff -c /dev/null llvm/test/Regression/CodeGen/CBackend/2004-08-09-va-end-null.ll:1.1 *** /dev/null Mon Aug 9 18:56:27 2004 --- llvm/test/Regression/CodeGen/CBackend/2004-08-09-va-end-null.ll Mon Aug 9 18:56:17 2004 *************** *** 0 **** --- 1,7 ---- + declare void %llvm.va_end(sbyte*) + + void %test() { + call void %llvm.va_end( sbyte* null ) + ret void + } + From lattner at cs.uiuc.edu Mon Aug 9 19:19:26 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Mon, 9 Aug 2004 19:19:26 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/CBackend/Writer.cpp Message-ID: <200408100019.TAA31048@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/CBackend: Writer.cpp updated: 1.192 -> 1.193 --- Log message: Paper over CBackend/2004-08-09-va-end-null.ll Note that this indicates a serious problem with the way we are emitting varargs, but this should not be properly fixed until after 1.3. This patch SHOULD go into 1.3. --- Diffs of the changes: (+7 -3) Index: llvm/lib/Target/CBackend/Writer.cpp diff -u llvm/lib/Target/CBackend/Writer.cpp:1.192 llvm/lib/Target/CBackend/Writer.cpp:1.193 --- llvm/lib/Target/CBackend/Writer.cpp:1.192 Sun Jul 25 17:36:35 2004 +++ llvm/lib/Target/CBackend/Writer.cpp Mon Aug 9 19:19:16 2004 @@ -1390,9 +1390,13 @@ Out << ")"; return; case Intrinsic::vaend: - Out << "va_end(*(va_list*)&"; - writeOperand(I.getOperand(1)); - Out << ")"; + if (!isa(I.getOperand(1))) { + Out << "va_end(*(va_list*)&"; + writeOperand(I.getOperand(1)); + Out << ")"; + } else { + Out << "va_end(*(va_list*)0)"; + } return; case Intrinsic::vacopy: Out << "0;"; From llvm at cs.uiuc.edu Mon Aug 9 20:59:10 2004 From: llvm at cs.uiuc.edu (LLVM) Date: Mon, 9 Aug 2004 20:59:10 -0500 Subject: [llvm-commits] CVS: llvm/tools/llvmc/ Message-ID: <200408100159.UAA02521@zion.cs.uiuc.edu> Changes in directory llvm/tools/llvmc: --- Log message: Directory /var/cvs/llvm/llvm/tools/llvmc added to the repository --- Diffs of the changes: (+0 -0) From lattner at cs.uiuc.edu Tue Aug 10 10:05:31 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 10:05:31 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/CodeEmitterGen.cpp Message-ID: <200408101505.KAA00954@apoc.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: CodeEmitterGen.cpp updated: 1.33 -> 1.34 --- Log message: This was a good idea, but until this does not break the build of lib/Target/Sparc, we should not use it. --- Diffs of the changes: (+3 -3) Index: llvm/utils/TableGen/CodeEmitterGen.cpp diff -u llvm/utils/TableGen/CodeEmitterGen.cpp:1.33 llvm/utils/TableGen/CodeEmitterGen.cpp:1.34 --- llvm/utils/TableGen/CodeEmitterGen.cpp:1.33 Mon Aug 9 14:10:43 2004 +++ llvm/utils/TableGen/CodeEmitterGen.cpp Tue Aug 10 10:05:18 2004 @@ -20,15 +20,15 @@ using namespace llvm; void CodeEmitterGen::run(std::ostream &o) { - CodeGenTarget Target; std::vector Insts = Records.getAllDerivedDefinitions("Instruction"); EmitSourceFileHeader("Machine Code Emitter", o); - std::string Namespace = Insts[0]->getValueAsString("Namespace") + "::"; + std::string Namespace = "V9::"; + std::string ClassName = "SparcV9CodeEmitter::"; //const std::string &Namespace = Inst->getValue("Namespace")->getName(); - o << "unsigned " << Target.getName() << "CodeEmitter::" + o << "unsigned " << ClassName << "getBinaryCodeForInstr(MachineInstr &MI) {\n" << " unsigned Value = 0;\n" << " DEBUG(std::cerr << MI);\n" From brukman at cs.uiuc.edu Tue Aug 10 10:29:33 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 10:29:33 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9.td Message-ID: <200408101529.KAA10170@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9.td updated: 1.35 -> 1.36 --- Log message: Define the target name so we can use it via TableGen. --- Diffs of the changes: (+1 -0) Index: llvm/lib/Target/SparcV9/SparcV9.td diff -u llvm/lib/Target/SparcV9/SparcV9.td:1.35 llvm/lib/Target/SparcV9/SparcV9.td:1.36 --- llvm/lib/Target/SparcV9/SparcV9.td:1.35 Mon Aug 9 14:13:27 2004 +++ llvm/lib/Target/SparcV9/SparcV9.td Tue Aug 10 10:29:15 2004 @@ -23,6 +23,7 @@ class InstV9 : Instruction { // SparcV9 instruction baseline field bits<32> Inst; + let Name = "SparcV9"; let Namespace = "V9"; bits<2> op; From lattner at cs.uiuc.edu Tue Aug 10 11:10:07 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 11:10:07 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200408101610.LAA12010@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.87 -> 1.88 --- Log message: Convert all Ii8 instructions over to the autogenerated asmprinter. --- Diffs of the changes: (+36 -36) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.87 llvm/lib/Target/X86/X86InstrInfo.td:1.88 --- llvm/lib/Target/X86/X86InstrInfo.td:1.87 Sun Aug 1 04:52:59 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Tue Aug 10 11:09:54 2004 @@ -134,7 +134,7 @@ class Im32 o, Format f> : Im; class Ii o, Format f, ImmType i> : X86Inst; -class Ii8 o, Format f> : Ii; +class Ii8 o, Format f, dag ops, string asm> : Ii<"", o, f, Imm8 >, II; class Ii16 o, Format f> : Ii; class Ii32 o, Format f> : Ii; @@ -287,9 +287,9 @@ def MOV8rr : I<0x88, MRMDestReg>, II<(ops R8 :$dst, R8 :$src), "mov $dst, $src">; def MOV16rr : I<0x89, MRMDestReg>, OpSize, II<(ops R16:$dst, R16 :$src), "mov $dst, $src">; def MOV32rr : I<0x89, MRMDestReg>, II<(ops R32:$dst, R32 :$src), "mov $dst, $src">; -def MOV8ri : Ii8 <"", 0xB0, AddRegFrm >, II<(ops R8 :$dst, i8imm :$src), "mov $dst, $src">; -def MOV16ri : Ii16 <"", 0xB8, AddRegFrm >, OpSize, II<(ops R16:$dst, i16imm:$src), "mov $dst, $src">; -def MOV32ri : Ii32 <"", 0xB8, AddRegFrm >, II<(ops R32:$dst, i32imm:$src), "mov $dst, $src">; +def MOV8ri : Ii8 <0xB0, AddRegFrm, (ops R8 :$dst, i8imm :$src), "mov $dst, $src">; +def MOV16ri : Ii16<"", 0xB8, AddRegFrm >, OpSize, II<(ops R16:$dst, i16imm:$src), "mov $dst, $src">; +def MOV32ri : Ii32<"", 0xB8, AddRegFrm >, II<(ops R32:$dst, i32imm:$src), "mov $dst, $src">; 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 @@ -490,15 +490,15 @@ def AND16rm : Im16 <"and", 0x23, MRMSrcMem >, OpSize; // R16 &= [mem16] def AND32rm : Im32 <"and", 0x23, MRMSrcMem >; // R32 &= [mem32] -def AND8ri : Ii8 <"and", 0x80, MRM4r >; +def AND8ri : Ii8 <0x80, MRM4r, (ops R8:$dst, R8:$src1, i8imm:$src2), "and $dst, $src2">; def AND16ri : Ii16 <"and", 0x81, MRM4r >, OpSize; def AND32ri : Ii32 <"and", 0x81, MRM4r >; 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 AND16ri8 : Ii8 <0x83, MRM4r, (ops R16:$dst, R16:$src1, i8imm:$src2), "and $dst, $src2" >, OpSize; // R16 &= imm8 +def AND32ri8 : Ii8 <0x83, MRM4r, (ops R32:$dst, R32:$src1, i8imm:$src2), "and $dst, $src2">; // R32 &= imm8 def AND16mi8 : Im16i8<"and", 0x83, MRM4m >, OpSize; // [mem16] &= imm8 def AND32mi8 : Im32i8<"and", 0x83, MRM4m >; // [mem32] &= imm8 @@ -516,15 +516,15 @@ def OR16rm : Im16 <"or" , 0x0B, MRMSrcMem >, OpSize; // R16 |= [mem16] def OR32rm : Im32 <"or" , 0x0B, MRMSrcMem >; // R32 |= [mem32] -def OR8ri : Ii8 <"or" , 0x80, MRM1r >; +def OR8ri : Ii8 <0x80, MRM1r, (ops R8:$dst, R8:$src1, i8imm:$src2), "or $dst, $src2">; def OR16ri : Ii16 <"or" , 0x81, MRM1r >, OpSize; def OR32ri : Ii32 <"or" , 0x81, MRM1r >; 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 OR16ri8 : Ii8 <0x83, MRM1r, (ops R8:$dst, R8:$src1, i8imm:$src2), "or $dst, $src2">, OpSize; // R16 |= imm8 +def OR32ri8 : Ii8 <0x83, MRM1r, (ops R32:$dst, R32:$src1, i8imm:$src2), "or $dst, $src2">; // R32 |= imm8 def OR16mi8 : Im16i8<"or" , 0x83, MRM1m >, OpSize; // [mem16] |= imm8 def OR32mi8 : Im32i8<"or" , 0x83, MRM1m >; // [mem32] |= imm8 @@ -542,15 +542,15 @@ def XOR16rm : Im16 <"xor", 0x33, MRMSrcMem >, OpSize; // R16 ^= [mem16] def XOR32rm : Im32 <"xor", 0x33, MRMSrcMem >; // R32 ^= [mem32] -def XOR8ri : Ii8 <"xor", 0x80, MRM6r >; +def XOR8ri : Ii8 <0x80, MRM6r, (ops R8:$dst, R8:$src1, i8imm:$src2), "xor $dst, $src2">; def XOR16ri : Ii16 <"xor", 0x81, MRM6r >, OpSize; def XOR32ri : Ii32 <"xor", 0x81, MRM6r >; 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 XOR16ri8 : Ii8 <0x83, MRM6r, (ops R16:$dst, R16:$src1, i8imm:$src2), "xor $dst, $src2">, OpSize; // R16 ^= imm8 +def XOR32ri8 : Ii8 <0x83, MRM6r, (ops R32:$dst, R32:$src1, i8imm:$src2), "xor $dst, $src2">; // R32 ^= imm8 def XOR16mi8 : Im16i8<"xor", 0x83, MRM6m >, OpSize; // [mem16] ^= imm8 def XOR32mi8 : Im32i8<"xor", 0x83, MRM6m >; // [mem32] ^= imm8 @@ -568,9 +568,9 @@ def SHL32mCL : Im32 <"shl", 0xD3, MRM4m > ; // [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 SHL8ri : Ii8 <0xC0, MRM4r, (ops R8:$dst, R8:$src1, i8imm:$src2), "shl $dst, $src2">; // R8 <<= imm8 +def SHL16ri : Ii8 <0xC1, MRM4r, (ops R16:$dst, R16:$src1, i8imm:$src2), "shl $dst, $src2">, OpSize; // R16 <<= imm8 +def SHL32ri : Ii8 <0xC1, MRM4r, (ops R32:$dst, R32:$src1, i8imm:$src2), "shl $dst, $src2">; // 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 @@ -587,9 +587,9 @@ def SHR32mCL : Im32 <"shr", 0xD3, MRM5m > ; // [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 SHR8ri : Ii8 <0xC0, MRM5r, (ops R8:$dst, R8:$src1, i8imm:$src2), "shr $dst, $src2">; // R8 >>= imm8 +def SHR16ri : Ii8 <0xC1, MRM5r, (ops R16:$dst, R16:$src1, i8imm:$src2), "shr $dst, $src2">, OpSize; // R16 >>= imm8 +def SHR32ri : Ii8 <0xC1, MRM5r, (ops R32:$dst, R32:$src1, i8imm:$src2), "shr $dst, $src2">; // 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 @@ -606,9 +606,9 @@ def SAR32mCL : Im32 <"sar", 0xD3, MRM7m > ; // [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 SAR8ri : Ii8 <0xC0, MRM7r, (ops R8:$dst, R8:$src1, i8imm:$src2), "sar $dst, $src2">; // R8 >>>= imm8 +def SAR16ri : Ii8 <0xC1, MRM7r, (ops R16:$dst, R16:$src1, i8imm:$src2), "sar $dst, $src2">, OpSize; // R16 >>>= imm8 +def SAR32ri : Ii8 <0xC1, MRM7r, (ops R32:$dst, R32:$src1, i8imm:$src2), "sar $dst, $src2">; // 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 @@ -622,9 +622,9 @@ def SHRD32mrCL : Im32 <"shrd", 0xAD, MRMDestMem>, TB; // [mem32] >>= [mem32],R32 cl } -def SHLD32rri8 : Ii8 <"shld", 0xA4, MRMDestReg>, TB; // R32 <<= R32,R32 imm8 +def SHLD32rri8 : Ii8 <0xA4, MRMDestReg, (ops R8:$dst, R8:$src1, i8imm:$src2), "shld $dst, $src2">, TB; // R32 <<= R32,R32 imm8 def SHLD32mri8 : Im32i8<"shld", 0xA4, MRMDestMem>, TB; // [mem32] <<= [mem32],R32 imm8 -def SHRD32rri8 : Ii8 <"shrd", 0xAC, MRMDestReg>, TB; // R32 >>= R32,R32 imm8 +def SHRD32rri8 : Ii8 <0xAC, MRMDestReg, (ops R16:$dst, R16:$src1, i8imm:$src2), "shrd $dst, $src2">, TB; // R32 >>= R32,R32 imm8 def SHRD32mri8 : Im32i8<"shrd", 0xAC, MRMDestMem>, TB; // [mem32] >>= [mem32],R32 imm8 @@ -639,15 +639,15 @@ def ADD16rm : Im16 <"add", 0x03, MRMSrcMem >, OpSize; // R16 += [mem16] def ADD32rm : Im32 <"add", 0x03, MRMSrcMem >; // R32 += [mem32] -def ADD8ri : Ii8 <"add", 0x80, MRM0r >; +def ADD8ri : Ii8 <0x80, MRM0r, (ops R8:$dst, R8:$src1, i8imm:$src2), "add $dst, $src2">; def ADD16ri : Ii16 <"add", 0x81, MRM0r >, OpSize; def ADD32ri : Ii32 <"add", 0x81, MRM0r >; 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 ADD16ri8 : Ii8 <0x83, MRM0r, (ops R16:$dst, R16:$src1, i8imm:$src2), "add $dst, $src2">, OpSize; +def ADD32ri8 : Ii8 <0x83, MRM0r, (ops R32:$dst, R32:$src1, i8imm:$src2), "add $dst, $src2">; def ADD16mi8 : Im16i8<"add", 0x83, MRM0m >, OpSize; // [mem16] += I8 def ADD32mi8 : Im32i8<"add", 0x83, MRM0m >; // [mem32] += I8 @@ -656,7 +656,7 @@ def ADC32mr : Im32 <"adc", 0x11, MRMDestMem>; // [mem32] += R32+Carry def ADC32rm : Im32 <"adc", 0x13, MRMSrcMem >; // R32 += [mem32]+Carry def ADC32ri : Ii32 <"adc", 0x81, MRM2r >; // R32 += I32+Carry -def ADC32ri8 : Ii8 <"adc", 0x83, MRM2r >; // R32 += I8+Carry +def ADC32ri8 : Ii8 <0x83, MRM2r, (ops R32:$dst, R32:$src1, i8imm:$src2), "adc $dst, $src2">; // R32 += I8+Carry def ADC32mi : Im32i32<"adc", 0x81, MRM2m >; // [mem32] += I32+Carry def ADC32mi8 : Im32i8 <"adc", 0x83, MRM2m >; // [mem32] += I8+Carry @@ -670,15 +670,15 @@ def SUB16rm : Im16 <"sub", 0x2B, MRMSrcMem >, OpSize; // R16 -= [mem16] def SUB32rm : Im32 <"sub", 0x2B, MRMSrcMem >; // R32 -= [mem32] -def SUB8ri : Ii8 <"sub", 0x80, MRM5r >; +def SUB8ri : Ii8 <0x80, MRM5r, (ops R8:$dst, R8:$src1, i8imm:$src2), "sub $dst, $src2">; def SUB16ri : Ii16 <"sub", 0x81, MRM5r >, OpSize; def SUB32ri : Ii32 <"sub", 0x81, MRM5r >; 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 SUB16ri8 : Ii8 <0x83, MRM5r, (ops R16:$dst, R16:$src1, i8imm:$src2), "sub $dst, $src2">, OpSize; +def SUB32ri8 : Ii8 <0x83, MRM5r, (ops R32:$dst, R32:$src1, i8imm:$src2), "sub $dst, $src2">; def SUB16mi8 : Im16i8<"sub", 0x83, MRM5m >, OpSize; // [mem16] -= I8 def SUB32mi8 : Im32i8<"sub", 0x83, MRM5m >; // [mem32] -= I8 @@ -687,7 +687,7 @@ def SBB32mr : Im32 <"sbb", 0x19, MRMDestMem>; // [mem32] -= R32+Carry def SBB32rm : Im32 <"sbb", 0x1B, MRMSrcMem >; // R32 -= [mem32]+Carry def SBB32ri : Ii32 <"sbb", 0x81, MRM3r >; // R32 -= I32+Carry -def SBB32ri8 : Ii8 <"sbb", 0x83, MRM3r >; // R32 -= I8+Carry +def SBB32ri8 : Ii8 <0x83, MRM3r, (ops R32:$dst, R32:$src1, i8imm:$src2), "sbb $dst, $src2">; // R32 -= I8+Carry def SBB32mi : Im32i32<"sbb", 0x81, MRM3m >; // [mem32] -= I32+Carry def SBB32mi8 : Im32i8 <"sbb", 0x83, MRM3m >; // [mem32] -= I8+Carry @@ -703,8 +703,8 @@ // 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 IMUL16rri8 : Ii8 <0x6B, MRMSrcReg, (ops R16:$dst, R16:$src1, i8imm:$src2), "imul $dst, $src1, $src2">, OpSize; // R16 = R16*I8 +def IMUL32rri8 : Ii8 <0x6B, MRMSrcReg, (ops R32:$dst, R32:$src1, i8imm:$src2), "imul $dst, $src1, $src2">; // 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 @@ -725,7 +725,7 @@ 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 TEST8ri : Ii8 <0xF6, MRM0r, (ops R8:$dst, R8:$src1, i8imm:$src2), "test $dst, $src2">; // 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 @@ -793,7 +793,7 @@ 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 CMP8ri : Ii8 <0x80, MRM7r, (ops R16:$dst, i8imm:$src), "cmp $dst, $src">; // 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 From lattner at cs.uiuc.edu Tue Aug 10 11:22:14 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 11:22:14 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200408101622.LAA13393@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.88 -> 1.89 --- Log message: Convert the Ii16 instructions over --- Diffs of the changes: (+26 -23) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.88 llvm/lib/Target/X86/X86InstrInfo.td:1.89 --- llvm/lib/Target/X86/X86InstrInfo.td:1.88 Tue Aug 10 11:09:54 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Tue Aug 10 11:22:02 2004 @@ -135,7 +135,7 @@ class Ii o, Format f, ImmType i> : X86Inst; class Ii8 o, Format f, dag ops, string asm> : Ii<"", o, f, Imm8 >, II; -class Ii16 o, Format f> : Ii; +class Ii16 o, Format f, dag ops, string asm> : Ii<"", o, f, Imm16>, II; class Ii32 o, Format f> : Ii; class Im8i8 o, Format f> : X86Inst; @@ -260,12 +260,15 @@ def IN32rr : I<0xED, RawFrm>, Imp<[DX],[EAX]>, // EAX = in I/O address DX II<(ops), "in %EAX, %DX">; -def IN8ri : Ii16<"", 0xE4, RawFrm>, Imp<[], [AL]>, // AL = in [I/O address] - II<(ops i16imm:$port), "in %AL, $port">; -def IN16ri : Ii16<"", 0xE5, RawFrm>, Imp<[], [AX]>, OpSize, // AX = in [I/O address] - II<(ops i16imm:$port), "in %AX, $port">; -def IN32ri : Ii16<"", 0xE5, RawFrm>, Imp<[],[EAX]>, // EAX = in [I/O address] - II<(ops i16imm:$port), "in %EAX, $port">; +def IN8ri : Ii16<0xE4, RawFrm, (ops i16imm:$port), // AL = in [I/O address] + "in %AL, $port">, + Imp<[], [AL]>; +def IN16ri : Ii16<0xE5, RawFrm, (ops i16imm:$port), // AX = in [I/O address] + "in %AX, $port">, + Imp<[], [AX]>, OpSize; +def IN32ri : Ii16<0xE5, RawFrm, (ops i16imm:$port), // EAX = in [I/O address] + "in %EAX, $port">, + Imp<[],[EAX]>; def OUT8rr : I<0xEE, RawFrm>, Imp<[DX, AL], []>, II<(ops), "out %DX, %AL">; @@ -274,12 +277,12 @@ def OUT32rr : I<0xEF, RawFrm>, Imp<[DX, EAX], []>, II<(ops), "out %DX, %EAX">; -def OUT8ir : Ii16<"", 0xE6, RawFrm>, Imp<[AL], []>, - II<(ops i16imm:$port), "out $port, %AL">; -def OUT16ir : Ii16<"", 0xE7, RawFrm>, Imp<[AX], []>, OpSize, - II<(ops i16imm:$port), "out $port, %AX">; -def OUT32ir : Ii16<"", 0xE7, RawFrm>, Imp<[EAX], []>, - II<(ops i16imm:$port), "out $port, %EAX">; +def OUT8ir : Ii16<0xE6, RawFrm, (ops i16imm:$port), + "out $port, %AL">, Imp<[AL], []>; +def OUT16ir : Ii16<0xE7, RawFrm, (ops i16imm:$port), + "out $port, %AX">, Imp<[AX], []>, OpSize; +def OUT32ir : Ii16<0xE7, RawFrm, (ops i16imm:$port), + "out $port, %EAX">, Imp<[EAX], []>; //===----------------------------------------------------------------------===// // Move Instructions... @@ -288,7 +291,7 @@ def MOV16rr : I<0x89, MRMDestReg>, OpSize, II<(ops R16:$dst, R16 :$src), "mov $dst, $src">; def MOV32rr : I<0x89, MRMDestReg>, II<(ops R32:$dst, R32 :$src), "mov $dst, $src">; def MOV8ri : Ii8 <0xB0, AddRegFrm, (ops R8 :$dst, i8imm :$src), "mov $dst, $src">; -def MOV16ri : Ii16<"", 0xB8, AddRegFrm >, OpSize, II<(ops R16:$dst, i16imm:$src), "mov $dst, $src">; +def MOV16ri : Ii16<0xB8, AddRegFrm, (ops R16:$dst, i16imm:$src), "mov $dst, $src">, OpSize; def MOV32ri : Ii32<"", 0xB8, AddRegFrm >, II<(ops R32:$dst, i32imm:$src), "mov $dst, $src">; def MOV8mi : Im8i8 <"mov", 0xC6, MRM0m >; // [mem8] = imm8 def MOV16mi : Im16i16<"mov", 0xC7, MRM0m >, OpSize; // [mem16] = imm16 @@ -491,7 +494,7 @@ def AND32rm : Im32 <"and", 0x23, MRMSrcMem >; // R32 &= [mem32] def AND8ri : Ii8 <0x80, MRM4r, (ops R8:$dst, R8:$src1, i8imm:$src2), "and $dst, $src2">; -def AND16ri : Ii16 <"and", 0x81, MRM4r >, OpSize; +def AND16ri : Ii16 <0x81, MRM4r, (ops R16:$dst, R16:$src1, i16imm:$src2), "and $dst, $src2">, OpSize; def AND32ri : Ii32 <"and", 0x81, MRM4r >; def AND8mi : Im8i8 <"and", 0x80, MRM4m >; // [mem8] &= imm8 def AND16mi : Im16i16<"and", 0x81, MRM4m >, OpSize; // [mem16] &= imm16 @@ -517,7 +520,7 @@ def OR32rm : Im32 <"or" , 0x0B, MRMSrcMem >; // R32 |= [mem32] def OR8ri : Ii8 <0x80, MRM1r, (ops R8:$dst, R8:$src1, i8imm:$src2), "or $dst, $src2">; -def OR16ri : Ii16 <"or" , 0x81, MRM1r >, OpSize; +def OR16ri : Ii16 <0x81, MRM1r, (ops R16:$dst, R16:$src1, i16imm:$src2), "or $dst, $src2">, OpSize; def OR32ri : Ii32 <"or" , 0x81, MRM1r >; def OR8mi : Im8i8 <"or" , 0x80, MRM1m >; // [mem8] |= imm8 def OR16mi : Im16i16<"or" , 0x81, MRM1m >, OpSize; // [mem16] |= imm16 @@ -543,7 +546,7 @@ def XOR32rm : Im32 <"xor", 0x33, MRMSrcMem >; // R32 ^= [mem32] def XOR8ri : Ii8 <0x80, MRM6r, (ops R8:$dst, R8:$src1, i8imm:$src2), "xor $dst, $src2">; -def XOR16ri : Ii16 <"xor", 0x81, MRM6r >, OpSize; +def XOR16ri : Ii16 <0x81, MRM6r, (ops R16:$dst, R16:$src1, i16imm:$src2), "xor $dst, $src2">, OpSize; def XOR32ri : Ii32 <"xor", 0x81, MRM6r >; def XOR8mi : Im8i8 <"xor", 0x80, MRM6m >; // [mem8] ^= R8 def XOR16mi : Im16i16<"xor", 0x81, MRM6m >, OpSize; // [mem16] ^= R16 @@ -640,7 +643,7 @@ def ADD32rm : Im32 <"add", 0x03, MRMSrcMem >; // R32 += [mem32] def ADD8ri : Ii8 <0x80, MRM0r, (ops R8:$dst, R8:$src1, i8imm:$src2), "add $dst, $src2">; -def ADD16ri : Ii16 <"add", 0x81, MRM0r >, OpSize; +def ADD16ri : Ii16 <0x81, MRM0r, (ops R16:$dst, R16:$src1, i16imm:$src2), "add $dst, $src2">, OpSize; def ADD32ri : Ii32 <"add", 0x81, MRM0r >; def ADD8mi : Im8i8 <"add", 0x80, MRM0m >; // [mem8] += I8 def ADD16mi : Im16i16<"add", 0x81, MRM0m >, OpSize; // [mem16] += I16 @@ -671,7 +674,7 @@ def SUB32rm : Im32 <"sub", 0x2B, MRMSrcMem >; // R32 -= [mem32] def SUB8ri : Ii8 <0x80, MRM5r, (ops R8:$dst, R8:$src1, i8imm:$src2), "sub $dst, $src2">; -def SUB16ri : Ii16 <"sub", 0x81, MRM5r >, OpSize; +def SUB16ri : Ii16 <0x81, MRM5r, (ops R16:$dst, R16:$src1, i16imm:$src2), "sub $dst, $src2">, OpSize; def SUB32ri : Ii32 <"sub", 0x81, MRM5r >; def SUB8mi : Im8i8 <"sub", 0x80, MRM5m >; // [mem8] -= I8 def SUB16mi : Im16i16<"sub", 0x81, MRM5m >, OpSize; // [mem16] -= I16 @@ -701,7 +704,7 @@ } // end Two Address instructions // These are suprisingly enough not two address instructions! -def IMUL16rri : Ii16 <"imul", 0x69, MRMSrcReg>, OpSize; // R16 = R16*I16 +def IMUL16rri : Ii16 <0x69, MRMSrcReg, (ops R16:$dst, R16:$src1, i16imm:$src2), "imul $dst, $src1, $src2">, OpSize; // R16 = R16*I16 def IMUL32rri : Ii32 <"imul", 0x69, MRMSrcReg>; // R32 = R32*I32 def IMUL16rri8 : Ii8 <0x6B, MRMSrcReg, (ops R16:$dst, R16:$src1, i8imm:$src2), "imul $dst, $src1, $src2">, OpSize; // R16 = R16*I8 def IMUL32rri8 : Ii8 <0x6B, MRMSrcReg, (ops R32:$dst, R32:$src1, i8imm:$src2), "imul $dst, $src1, $src2">; // R32 = R32*I8 @@ -725,8 +728,8 @@ def TEST16rm : Im16 <"test", 0x85, MRMSrcMem >, OpSize; // flags = R16 & [mem16] def TEST32rm : Im32 <"test", 0x85, MRMSrcMem >; // flags = R32 & [mem32] -def TEST8ri : Ii8 <0xF6, MRM0r, (ops R8:$dst, R8:$src1, i8imm:$src2), "test $dst, $src2">; // flags = R8 & imm8 -def TEST16ri : Ii16 <"test", 0xF7, MRM0r >, OpSize; // flags = R16 & imm16 +def TEST8ri : Ii8 <0xF6, MRM0r, (ops R8:$dst, i8imm:$src), "test $dst, $src">; // flags = R8 & imm8 +def TEST16ri : Ii16 <0xF7, MRM0r, (ops R16:$dst, i16imm:$src), "test $dst, $src">, 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 @@ -794,7 +797,7 @@ def CMP16rm : Im16 <"cmp", 0x3B, MRMSrcMem >, OpSize; // compare R16, [mem16] def CMP32rm : Im32 <"cmp", 0x3B, MRMSrcMem >; // compare R32, [mem32] def CMP8ri : Ii8 <0x80, MRM7r, (ops R16:$dst, i8imm:$src), "cmp $dst, $src">; // compare R8, imm8 -def CMP16ri : Ii16 <"cmp", 0x81, MRM7r >, OpSize; // compare R16, imm16 +def CMP16ri : Ii16 <0x81, MRM7r, (ops R16:$dst, i16imm:$src), "cmp $dst, $src">, 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 From reid at x10sys.com Tue Aug 10 11:26:11 2004 From: reid at x10sys.com (Reid Spencer) Date: Tue, 10 Aug 2004 11:26:11 -0500 Subject: [llvm-commits] CVS: llvm/tools/llvmc/llvmc.cpp Message-ID: <200408101626.LAA12528@zion.cs.uiuc.edu> Changes in directory llvm/tools/llvmc: llvmc.cpp added (r1.1) --- Log message: First "do nothing" version of the LLVM Compiler Driver. This version just processes command line arguments and allows --help to be used. --- Diffs of the changes: (+167 -0) Index: llvm/tools/llvmc/llvmc.cpp diff -c /dev/null llvm/tools/llvmc/llvmc.cpp:1.1 *** /dev/null Tue Aug 10 11:26:11 2004 --- llvm/tools/llvmc/llvmc.cpp Tue Aug 10 11:26:01 2004 *************** *** 0 **** --- 1,167 ---- + //===--- llvmc.cpp - The LLVM Compiler Driver -----------------------------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by Reid Spencerand is distributed under the + // University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This tool provides a single point of access to the LLVM compilation tools. + // It has many options. To discover the options supported please refer to the + // tools' manual page (docs/CommandGuide/html/llvmc.html) or run the tool with + // the --help option. + // + //===------------------------------------------------------------------------=== + + #include "llvm/Driver/CompilerDriver.h" + #include "llvm/System/Signals.h" + #include "Support/CommandLine.h" + #include + + using namespace llvm; + + //===------------------------------------------------------------------------=== + //=== PHASE OPTIONS + //===------------------------------------------------------------------------=== + static cl::opt FinalPhase( + cl::desc("Choose final phase of compilation:"), + cl::values( + clEnumValN(CompilerDriver::PREPROCESSING,"E", + "Stop compilation after pre-processing"), + clEnumValN(CompilerDriver::OPTIMIZATION,"c", + "Stop compilation after source code translation and optimization"), + clEnumValN(CompilerDriver::ASSEMBLY,"S", + "Stop compilation after assembly"), + clEnumValEnd + ) + ); + + //===------------------------------------------------------------------------=== + //=== OPTIMIZATION OPTIONS + //===------------------------------------------------------------------------=== + static cl::opt OptLevel( + cl::desc("Choose level of optimization to apply:"), + cl::values( + clEnumValN(CompilerDriver::OPT_FAST_COMPILE,"O0", + "Optimize for compilation speed, not execution speed."), + clEnumValN(CompilerDriver::OPT_FAST_COMPILE,"O1", + "Optimize for compilation speed, not execution speed."), + clEnumValN(CompilerDriver::OPT_SIMPLE,"O2", + "Perform simple translation time optimizations"), + clEnumValN(CompilerDriver::OPT_AGGRESSIVE,"O3", + "Perform aggressive translation time optimizations"), + clEnumValN(CompilerDriver::OPT_LINK_TIME,"O4", + "Perform link time optimizations"), + clEnumValN(CompilerDriver::OPT_AGGRESSIVE_LINK_TIME,"O5", + "Perform aggressive link time optimizations"), + clEnumValEnd + ) + ); + + //===------------------------------------------------------------------------=== + //=== TOOL OPTIONS + //===------------------------------------------------------------------------=== + + static cl::opt PPToolOpts("Tpp", cl::ZeroOrMore, + cl::desc("Pass specific options to the pre-processor")); + + static cl::opt AsmToolOpts("Tasm", cl::ZeroOrMore, + cl::desc("Pass specific options to the assembler")); + + static cl::opt OptToolOpts("Topt", cl::ZeroOrMore, + cl::desc("Pass specific options to the optimizer")); + + static cl::opt LinkToolOpts("Tlink", cl::ZeroOrMore, + cl::desc("Pass specific options to the linker")); + + //===------------------------------------------------------------------------=== + //=== INPUT OPTIONS + //===------------------------------------------------------------------------=== + + static cl::list LibPaths("L", cl::Prefix, + cl::desc("Specify a library search path"), cl::value_desc("directory")); + + static cl::list Libraries("l", cl::Prefix, + cl::desc("Specify libraries to link to"), cl::value_desc("library prefix")); + + + //===------------------------------------------------------------------------=== + //=== OUTPUT OPTIONS + //===------------------------------------------------------------------------=== + + static cl::opt OutputFilename("o", cl::init("a.out"), + cl::desc("Override output filename"), cl::value_desc("filename")); + + static cl::opt OutputMachne("m", cl::Prefix, + cl::desc("Specify a target machine"), cl::value_desc("machine")); + + static cl::opt Native("native", + cl::desc("Generative native object and executables instead of bytecode")); + + //===------------------------------------------------------------------------=== + //=== INFORMATION OPTIONS + //===------------------------------------------------------------------------=== + + static cl::opt NoOperation("no-operation", cl::Optional, + cl::desc("Do not perform actions")); + + static cl::alias NoOp("n", cl::Optional, + cl::desc("Alias for -no-operation"), cl::aliasopt(NoOperation)); + + static cl::opt Verbose("verbose", cl::Optional, + cl::desc("Print out each action taken")); + + static cl::alias VerboseAlias("v", cl::Optional, + cl::desc("Alias for -verbose"), cl::aliasopt(Verbose)); + + static cl::opt TimeActions("time-actions", cl::Optional, + cl::desc("Print execution time for each action taken")); + + //===------------------------------------------------------------------------=== + //=== ADVANCED OPTIONS + //===------------------------------------------------------------------------=== + + static cl::list ConfigFiles("config-dir", cl::Optional, + cl::desc("Specify a configuration directory to override defaults")); + + static cl::opt EmitRawCode("emit-raw-code", cl::Hidden, + cl::desc("Emit raw, unoptimized code")); + + //===------------------------------------------------------------------------=== + //=== POSITIONAL OPTIONS + //===------------------------------------------------------------------------=== + + static cl::list Files(cl::Positional, cl::OneOrMore, + cl::desc("Source and object files")); + + + /// @brief The main program for llvmc + int main(int argc, char **argv) { + // Make sure we print stack trace if we get bad signals + PrintStackTraceOnErrorSignal(); + + // Parse the command line options + cl::ParseCommandLineOptions(argc, argv, + " LLVM Compilation Driver (llvmc)\n\n" + " This program provides easy invocation of the LLVM tool set\n" + " and source language compiler tools.\n" + ); + + // Construct the CompilerDriver object + //CompilerDriver CD; + + // Set the options for the Compiler Driver + + // Tell the driver to do its thing + int result = 0; + // result = CD.execute(); + if (result != 0) { + std::cerr << argv[0] << ": Error executing actions. Terminated.\n"; + return result; + } + + // All is good, return success + return 0; + } + From reid at x10sys.com Tue Aug 10 11:27:18 2004 From: reid at x10sys.com (Reid Spencer) Date: Tue, 10 Aug 2004 11:27:18 -0500 Subject: [llvm-commits] CVS: llvm/tools/llvmc/Makefile Message-ID: <200408101627.LAA12556@zion.cs.uiuc.edu> Changes in directory llvm/tools/llvmc: Makefile added (r1.1) --- Log message: Initial makefile for the LLVM Compiler Driver. --- Diffs of the changes: (+13 -0) Index: llvm/tools/llvmc/Makefile diff -c /dev/null llvm/tools/llvmc/Makefile:1.1 *** /dev/null Tue Aug 10 11:27:18 2004 --- llvm/tools/llvmc/Makefile Tue Aug 10 11:27:08 2004 *************** *** 0 **** --- 1,13 ---- + ##===- tools/llvmc/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 = ../.. + TOOLNAME = llvmc + USEDLIBS = asmparser bcreader bcwriter vmcore support.a + + include $(LEVEL)/Makefile.common From reid at x10sys.com Tue Aug 10 11:29:29 2004 From: reid at x10sys.com (Reid Spencer) Date: Tue, 10 Aug 2004 11:29:29 -0500 Subject: [llvm-commits] CVS: llvm/tools/llvmc/CompilerDriver.h llvmc.cpp Message-ID: <200408101629.LAA12592@zion.cs.uiuc.edu> Changes in directory llvm/tools/llvmc: CompilerDriver.h added (r1.1) llvmc.cpp updated: 1.1 -> 1.2 --- Log message: Move CompilerDriver.h here. --- Diffs of the changes: (+76 -1) Index: llvm/tools/llvmc/CompilerDriver.h diff -c /dev/null llvm/tools/llvmc/CompilerDriver.h:1.1 *** /dev/null Tue Aug 10 11:29:28 2004 --- llvm/tools/llvmc/CompilerDriver.h Tue Aug 10 11:29:18 2004 *************** *** 0 **** --- 1,75 ---- + //===- CompilerDriver.h - Compiler Driver ---------------------------------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by Reid Spencer and is distributed under the + // University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file declares the CompilerDriver class which implements the bulk of the + // LLVM Compiler Driver program (llvmc). + // + //===------------------------------------------------------------------------=== + + namespace llvm { + /// This class provides the high level interface to the LLVM Compiler Driver. + /// The driver's purpose is to make it easier for compiler writers and users + /// of LLVM to utilize the compiler toolkits and LLVM toolset by learning only + /// the interface of one program (llvmc). + /// + /// @see llvmc.cpp + /// @brief The interface to the LLVM Compiler Driver. + class CompilerDriver { + /// @name Types + /// @{ + public: + typedef unsigned OptimizationLevel; + enum Phases { + PREPROCESSING, ///< Source language combining, filtering, substitution + TRANSLATION, ///< Translate source -> LLVM bytecode/assembly + OPTIMIZATION, ///< Optimize translation result + LINKING, ///< Link bytecode and native code + ASSEMBLY, ///< Convert program to executable + }; + + enum OptimizationLevels { + OPT_NONE, + OPT_FAST_COMPILE, + OPT_SIMPLE, + OPT_AGGRESSIVE, + OPT_LINK_TIME, + OPT_AGGRESSIVE_LINK_TIME + }; + + /// @} + /// @name Constructors + /// @{ + public: + CompilerDriver(); + + /// @} + /// @name Accessors + /// @{ + public: + void execute(); ///< Execute the actions requested + + /// @} + /// @name Mutators + /// @{ + public: + /// @brief Set the optimization level for the compilation + void setOptimization( OptimizationLevel level ); + void setFinalPhase( Phases phase ); + + /// @} + /// @name Data + /// @{ + public: + Phases finalPhase; + OptimizationLevel optLevel; + + /// @} + + }; + } Index: llvm/tools/llvmc/llvmc.cpp diff -u llvm/tools/llvmc/llvmc.cpp:1.1 llvm/tools/llvmc/llvmc.cpp:1.2 --- llvm/tools/llvmc/llvmc.cpp:1.1 Tue Aug 10 11:26:01 2004 +++ llvm/tools/llvmc/llvmc.cpp Tue Aug 10 11:29:18 2004 @@ -14,7 +14,7 @@ // //===------------------------------------------------------------------------=== -#include "llvm/Driver/CompilerDriver.h" +#include "CompilerDriver.h" #include "llvm/System/Signals.h" #include "Support/CommandLine.h" #include From reid at x10sys.com Tue Aug 10 11:38:28 2004 From: reid at x10sys.com (Reid Spencer) Date: Tue, 10 Aug 2004 11:38:28 -0500 Subject: [llvm-commits] CVS: llvm/docs/CommandLine.html Message-ID: <200408101638.LAA12723@zion.cs.uiuc.edu> Changes in directory llvm/docs: CommandLine.html updated: 1.23 -> 1.24 --- Log message: Fixed some spellos and grammaros. --- Diffs of the changes: (+3 -3) Index: llvm/docs/CommandLine.html diff -u llvm/docs/CommandLine.html:1.23 llvm/docs/CommandLine.html:1.24 --- llvm/docs/CommandLine.html:1.23 Thu Jul 15 19:10:54 2004 +++ llvm/docs/CommandLine.html Tue Aug 10 11:38:18 2004 @@ -458,10 +458,10 @@

      The answer is that it uses a table driven generic parser (unless you specify your own parser, as described in the Extension -Guide). This parser maps literal strings to whatever type is required, are +Guide). This parser maps literal strings to whatever type is required, and requires you to tell it what this mapping should be.

      -

      Lets say that we would like to add four optimizations levels to our +

      Lets say that we would like to add four optimization levels to our optimizer, using the standard flags "-g", "-O0", "-O1", and "-O2". We could easily implement this with boolean options like above, but there are several problems with this strategy:

      @@ -1709,7 +1709,7 @@ Chris Lattner
      LLVM Compiler Infrastructure
      - Last modified: $Date: 2004/07/16 00:10:54 $ + Last modified: $Date: 2004/08/10 16:38:18 $ From reid at x10sys.com Tue Aug 10 11:41:06 2004 From: reid at x10sys.com (Reid Spencer) Date: Tue, 10 Aug 2004 11:41:06 -0500 Subject: [llvm-commits] CVS: llvm/docs/CompilerDriver.html Message-ID: <200408101641.LAA12790@zion.cs.uiuc.edu> Changes in directory llvm/docs: CompilerDriver.html updated: 1.1 -> 1.2 --- Log message: Finish HTMLizing the document. Configuration section is very crufty. --- Diffs of the changes: (+33 -95) Index: llvm/docs/CompilerDriver.html diff -u llvm/docs/CompilerDriver.html:1.1 llvm/docs/CompilerDriver.html:1.2 --- llvm/docs/CompilerDriver.html:1.1 Sun Aug 8 22:08:29 2004 +++ llvm/docs/CompilerDriver.html Tue Aug 10 11:40:56 2004 @@ -336,7 +336,7 @@
      Configuration Files
      -

      Types of Files

      +

      File Types

      There are two types of configuration files: the master configuration file and the language specific configuration file. The master configuration file contains the general configuration of llvmc itself and is supplied @@ -405,100 +405,38 @@

      -
      - Master Configuration Items -
      -
      -
      -
      -=head3 Section: [lang=I]
      -
      -This section provides the master configuration data for a given language. The
      -language specific data will be found in a file named I.
      -
      -=over
      -
      -=item CI
      -
      -This adds the I specified to the list of recognized suffixes for
      -the I identified in the section. As many suffixes as are commonly used
      -for source files for the I should be specified. 
      -
      -=back
      -
      -=begin html
      -
      -

      For example, the following might appear for C++: -

      
      -[lang=C++]
      -suffix=.cpp
      -suffix=.cxx
      -suffix=.C
      -

      - -=end html -
      -
      - - -
      - Language Specific Configuration Items -
      +
      -
      -=head3 Section: [general]
      -
      -=over
      -
      -=item C
      -
      -This item specifies whether the language has a pre-processing phase or not. This
      -controls whether the B<-E> option works for the language or not.
      -
      -=item C
      -
      -This item specifies the kind of output the language's compiler generates. The
      -choices are either bytecode (C) or LLVM assembly (C).
      -
      -=back
      -
      -=head3 Section: [-O0]
      -
      -=over
      -
      -=item CI
      -
      -This item specifies the I to use for pre-processing the input.
      -
      -=over
      -
      -Valid substitutions for this item are:
      -
      -=item %in%
      -
      -The input source file.
      -
      -=item %out%
      -
      -The output file.
      -
      -=item %options%
      -
      -Any pre-processing specific options (e.g. B<-I>).
      -
      -=back
      -
      -=item CI
      -
      -This item specifies the I to use for translating the source
      -language input into the output format given by the C item.
      -
      -=item CI
      -
      -This item specifies the I for optimizing the translator's output.
      -
      -=back
      -
      +

      The following description of configuration items is syntax-less and simply + uses a naming hierarchy to describe the configuration items. Whatever + syntax is chosen will need to map the hierarchy to the given syntax.

      + + + + + + + + + + + + + + + + + + + + + +
      NameValue TypeDescription
      Capabilities.hasPreProcessorbooleanThis item specifies whether the language has a + pre-processing phase or not. This controls whether the B<-E> option works + for the language or not.
      Capabilities.outputFormat"bc" or "ll"This item specifies the kind of output the language's + compiler generates. The choices are either bytecode (bc) or LLVM + assembly (ll).
      Capabilities.understandsOptimizationbooleanIndicates whether the compiler for this language understands the + -O options or not
      @@ -564,7 +502,7 @@ src="http://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01!">Reid Spencer
      The LLVM Compiler Infrastructure
      -Last modified: $Date: 2004/08/09 03:08:29 $ +Last modified: $Date: 2004/08/10 16:40:56 $ From brukman at cs.uiuc.edu Tue Aug 10 12:37:25 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 12:37:25 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9_F2.td SparcV9_F3.td SparcV9_F4.td Message-ID: <200408101737.MAA13774@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9_F2.td updated: 1.10 -> 1.11 SparcV9_F3.td updated: 1.19 -> 1.20 SparcV9_F4.td updated: 1.12 -> 1.13 --- Log message: Fix comment header, specify type of file `tablegen'. --- Diffs of the changes: (+3 -3) Index: llvm/lib/Target/SparcV9/SparcV9_F2.td diff -u llvm/lib/Target/SparcV9/SparcV9_F2.td:1.10 llvm/lib/Target/SparcV9/SparcV9_F2.td:1.11 --- llvm/lib/Target/SparcV9/SparcV9_F2.td:1.10 Sun Apr 25 02:04:49 2004 +++ llvm/lib/Target/SparcV9/SparcV9_F2.td Tue Aug 10 12:37:14 2004 @@ -1,4 +1,4 @@ -//===- SparcV9_F2.td - Format 2 instructions: SparcV9 Target --------------===// +//===- SparcV9_F2.td - SparcV9 Format 2 instructions -------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // Index: llvm/lib/Target/SparcV9/SparcV9_F3.td diff -u llvm/lib/Target/SparcV9/SparcV9_F3.td:1.19 llvm/lib/Target/SparcV9/SparcV9_F3.td:1.20 --- llvm/lib/Target/SparcV9/SparcV9_F3.td:1.19 Sun Apr 25 02:04:49 2004 +++ llvm/lib/Target/SparcV9/SparcV9_F3.td Tue Aug 10 12:37:14 2004 @@ -1,4 +1,4 @@ -//===- SparcV9_F3.td - Format 3 Instructions: SparcV9 Target --------------===// +//===- SparcV9_F3.td - SparcV9 Format 3 Instructions -------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // Index: llvm/lib/Target/SparcV9/SparcV9_F4.td diff -u llvm/lib/Target/SparcV9/SparcV9_F4.td:1.12 llvm/lib/Target/SparcV9/SparcV9_F4.td:1.13 --- llvm/lib/Target/SparcV9/SparcV9_F4.td:1.12 Sun Apr 25 02:04:49 2004 +++ llvm/lib/Target/SparcV9/SparcV9_F4.td Tue Aug 10 12:37:14 2004 @@ -1,4 +1,4 @@ -//===- SparcV9_F4.td - Format 4 instructions: SparcV9 Target --------------===// +//===- SparcV9_F4.td - SparcV9 Format 4 instructions -------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // From brukman at cs.uiuc.edu Tue Aug 10 13:08:05 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 13:08:05 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Message-ID: <200408101808.NAA16998@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCInstrFormats.td updated: 1.6 -> 1.7 --- Log message: Fix DForm_4: format is `op r, r, i' --- Diffs of the changes: (+3 -2) Index: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.6 llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.7 --- llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.6 Mon Aug 9 14:13:25 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Tue Aug 10 13:07:55 2004 @@ -139,7 +139,6 @@ class DForm_2_r0 opcode, bit ppc64, bit vmx> : DForm_base { let Arg1Type = Gpr0.Value; - let B = 0; } // Currently we make the use/def reg distinction in ISel, not tablegen @@ -147,7 +146,9 @@ : DForm_1; class DForm_4 opcode, bit ppc64, bit vmx> - : DForm_1; + : DForm_base { + let Arg2Type = Zimm16.Value; +} class DForm_4_zero opcode, bit ppc64, bit vmx> : DForm_1 { From brukman at cs.uiuc.edu Tue Aug 10 13:14:14 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 13:14:14 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9RegisterInfo.td SparcV9_Reg.td Message-ID: <200408101814.NAA17141@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9RegisterInfo.td added (r1.1) SparcV9_Reg.td (r1.9) removed --- Log message: Renamed SparcV9_Reg.td -> SparcV9RegisterInfo.td for consistency. --- Diffs of the changes: (+41 -0) Index: llvm/lib/Target/SparcV9/SparcV9RegisterInfo.td diff -c /dev/null llvm/lib/Target/SparcV9/SparcV9RegisterInfo.td:1.1 *** /dev/null Tue Aug 10 13:14:14 2004 --- llvm/lib/Target/SparcV9/SparcV9RegisterInfo.td Tue Aug 10 13:14:04 2004 *************** *** 0 **** --- 1,41 ---- + //===- SparcV9_Reg.td - SparcV9 Register definitions ----------------------===// + // + // 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 SparcV9 register file + //===----------------------------------------------------------------------===// + + // Ri - One of the 32 64 bit integer registers + class Ri num> : Register { + field bits<5> Num = num; // Numbers are identified with a 5 bit ID + } + + let Namespace = "SparcV9" 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>; + // 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; From brukman at cs.uiuc.edu Tue Aug 10 13:15:41 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 13:15:41 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9InstrInfo.td SparcV9.td Message-ID: <200408101815.NAA17206@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9InstrInfo.td added (r1.1) SparcV9.td updated: 1.36 -> 1.37 --- Log message: * Instruction definitions moved to SparcV9InstrInfo.td for consistency * Defined PHI instruction and SparcV9 subclass of Target --- Diffs of the changes: (+805 -753) Index: llvm/lib/Target/SparcV9/SparcV9InstrInfo.td diff -c /dev/null llvm/lib/Target/SparcV9/SparcV9InstrInfo.td:1.1 *** /dev/null Tue Aug 10 13:15:41 2004 --- llvm/lib/Target/SparcV9/SparcV9InstrInfo.td Tue Aug 10 13:15:31 2004 *************** *** 0 **** --- 1,780 ---- + //===- SparcV9InstrInfo.td - SparcV9 Instruction defs ------*- tablegen -*-===// + // + // 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 files declares the set of instructions used in the SparcV9 backend. + // + //===----------------------------------------------------------------------===// + + class InstV9 : Instruction { // SparcV9 instruction baseline + field bits<32> Inst; + + let Namespace = "V9"; + + bits<2> op; + let Inst{31-30} = op; // Top two bits are the 'op' field + + // 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? + } + + class Pseudo : InstV9 { + let Name = n; + let Inst{0-31} = 0; + } + + include "SparcV9_F2.td" + include "SparcV9_F3.td" + include "SparcV9_F4.td" + + //===----------------------------------------------------------------------===// + // Instruction list + //===----------------------------------------------------------------------===// + + // Pseudo-instructions + def PHI : Pseudo<"phi">; + + // Section A.2: Add - p137 + def ADDr : F3_1<2, 0b000000, "add">; // add rs1, rs2, rd + def ADDi : F3_2<2, 0b000000, "add">; // add rs1, imm, rd + def ADDccr : F3_1<2, 0b010000, "addcc">; // addcc rs1, rs2, rd + def ADDcci : F3_2<2, 0b010000, "addcc">; // addcc rs1, imm, rd + def ADDCr : F3_1<2, 0b001000, "addC">; // addC rs1, rs2, rd + def ADDCi : F3_2<2, 0b001000, "addC">; // addC rs1, imm, rd + def ADDCccr : F3_1<2, 0b011000, "addCcc">; // addCcc rs1, rs2, rd + def ADDCcci : F3_2<2, 0b011000, "addCcc">; // addCcc rs1, imm, rd + + // Section A.3: Branch on Integer Register with Prediction - p138 + let op2 = 0b011 in { + def BRZ : F2_4<0b001, "brz">; // Branch on rs1 == 0 + def BRLEZ : F2_4<0b010, "brlez">; // Branch on rs1 <= 0 + def BRLZ : F2_4<0b011, "brlz">; // Branch on rs1 < 0 + def BRNZ : F2_4<0b101, "brnz">; // Branch on rs1 != 0 + def BRGZ : F2_4<0b110, "brgz">; // Branch on rs1 > 0 + def BRGEZ : F2_4<0b111, "brgez">; // Branch on rs1 >= 0 + } + + // Section A.4: Branch on Floating-Point Condition Codes (FBfcc) p140 + // The following deprecated instructions don't seem to play nice on SparcV9 + /* + let isDeprecated = 1 in { + let op2 = 0b110 in { + def FBA : F2_2<0b1000, "fba">; // Branch always + def FBN : F2_2<0b0000, "fbn">; // Branch never + def FBU : F2_2<0b0111, "fbu">; // Branch on unordered + def FBG : F2_2<0b0110, "fbg">; // Branch > + def FBUG : F2_2<0b0101, "fbug">; // Branch on unordered or > + def FBL : F2_2<0b0100, "fbl">; // Branch < + def FBUL : F2_2<0b0011, "fbul">; // Branch on unordered or < + def FBLG : F2_2<0b0010, "fblg">; // Branch < or > + def FBNE : F2_2<0b0001, "fbne">; // Branch != + def FBE : F2_2<0b1001, "fbe">; // Branch == + def FBUE : F2_2<0b1010, "fbue">; // Branch on unordered or == + def FBGE : F2_2<0b1011, "fbge">; // Branch > or == + def FBUGE : F2_2<0b1100, "fbuge">; // Branch unord or > or == + def FBLE : F2_2<0b1101, "fble">; // Branch < or == + def FBULE : F2_2<0b1110, "fbule">; // Branch unord or < or == + def FBO : F2_2<0b1111, "fbo">; // Branch on ordered + } + } + */ + + // We now make these same opcodes represent the FBPfcc instructions + let op2 = 0b101 in { + def FBA : F2_3<0b1000, "fba">; // Branch always + def FBN : F2_3<0b0000, "fbn">; // Branch never + def FBU : F2_3<0b0111, "fbu">; // Branch on unordered + def FBG : F2_3<0b0110, "fbg">; // Branch > + def FBUG : F2_3<0b0101, "fbug">; // Branch on unordered or > + def FBL : F2_3<0b0100, "fbl">; // Branch < + def FBUL : F2_3<0b0011, "fbul">; // Branch on unordered or < + def FBLG : F2_3<0b0010, "fblg">; // Branch < or > + def FBNE : F2_3<0b0001, "fbne">; // Branch != + def FBE : F2_3<0b1001, "fbe">; // Branch == + def FBUE : F2_3<0b1010, "fbue">; // Branch on unordered or == + def FBGE : F2_3<0b1011, "fbge">; // Branch > or == + def FBUGE : F2_3<0b1100, "fbuge">; // Branch unord or > or == + def FBLE : F2_3<0b1101, "fble">; // Branch < or == + def FBULE : F2_3<0b1110, "fbule">; // Branch unord or < or == + def FBO : F2_3<0b1111, "fbo">; // Branch on ordered + } + + // Section A.5: Branch on FP condition codes with prediction - p143 + // Not used in the SparcV9 backend (directly) + /* + let op2 = 0b101 in { + def FBPA : F2_3<0b1000, "fba">; // Branch always + def FBPN : F2_3<0b0000, "fbn">; // Branch never + def FBPU : F2_3<0b0111, "fbu">; // Branch on unordered + def FBPG : F2_3<0b0110, "fbg">; // Branch > + def FBPUG : F2_3<0b0101, "fbug">; // Branch on unordered or > + def FBPL : F2_3<0b0100, "fbl">; // Branch < + def FBPUL : F2_3<0b0011, "fbul">; // Branch on unordered or < + def FBPLG : F2_3<0b0010, "fblg">; // Branch < or > + def FBPNE : F2_3<0b0001, "fbne">; // Branch != + def FBPE : F2_3<0b1001, "fbe">; // Branch == + def FBPUE : F2_3<0b1010, "fbue">; // Branch on unordered or == + def FBPGE : F2_3<0b1011, "fbge">; // Branch > or == + def FBPUGE : F2_3<0b1100, "fbuge">; // Branch unord or > or == + def FBPLE : F2_3<0b1101, "fble">; // Branch < or == + def FBPULE : F2_3<0b1110, "fbule">; // Branch unord or < or == + def FBPO : F2_3<0b1111, "fbo">; // Branch on ordered + } + */ + + // Section A.6: Branch on Integer condition codes (Bicc) - p146 + /* + let isDeprecated = 1 in { + let op2 = 0b010 in { + def BA : F2_2<0b1000, "ba">; // Branch always + def BN : F2_2<0b0000, "bn">; // Branch never + def BNE : F2_2<0b1001, "bne">; // Branch != + def BE : F2_2<0b0001, "be">; // Branch == + def BG : F2_2<0b1010, "bg">; // Branch > + def BLE : F2_2<0b0010, "ble">; // Branch <= + def BGE : F2_2<0b1011, "bge">; // Branch >= + def BL : F2_2<0b0011, "bl">; // Branch < + def BGU : F2_2<0b1100, "bgu">; // Branch unsigned > + def BLEU : F2_2<0b0100, "bleu">; // Branch unsigned <= + def BCC : F2_2<0b1101, "bcc">; // Branch unsigned >= + def BCS : F2_2<0b0101, "bcs">; // Branch unsigned <= + def BPOS : F2_2<0b1110, "bpos">; // Branch on positive + def BNEG : F2_2<0b0110, "bneg">; // Branch on negative + def BVC : F2_2<0b1111, "bvc">; // Branch on overflow clear + def BVS : F2_2<0b0111, "bvs">; // Branch on overflow set + } + } + */ + + // Using the format of A.7 instructions... + let op2 = 0b001 in { + let cc = 0 in { // BA and BN don't read condition codes + def BA : F2_3<0b1000, "ba">; // Branch always + def BN : F2_3<0b0000, "bn">; // Branch never + } + def BNE : F2_3<0b1001, "bne">; // Branch != + def BE : F2_3<0b0001, "be">; // Branch == + def BG : F2_3<0b1010, "bg">; // Branch > + def BLE : F2_3<0b0010, "ble">; // Branch <= + def BGE : F2_3<0b1011, "bge">; // Branch >= + def BL : F2_3<0b0011, "bl">; // Branch < + def BGU : F2_3<0b1100, "bgu">; // Branch unsigned > + def BLEU : F2_3<0b0100, "bleu">; // Branch unsigned <= + def BCC : F2_3<0b1101, "bcc">; // Branch unsigned >= + def BCS : F2_3<0b0101, "bcs">; // Branch unsigned <= + def BPOS : F2_3<0b1110, "bpos">; // Branch on positive + def BNEG : F2_3<0b0110, "bneg">; // Branch on negative + def BVC : F2_3<0b1111, "bvc">; // Branch on overflow clear + def BVS : F2_3<0b0111, "bvs">; // Branch on overflow set + } + + // Section A.7: Branch on integer condition codes with prediction - p148 + // Not used in the SparcV9 backend + /* + let op2 = 0b001 in { + def BPA : F2_3<0b1000, "bpa">; // Branch always + def BPN : F2_3<0b0000, "bpn">; // Branch never + def BPNE : F2_3<0b1001, "bpne">; // Branch != + def BPE : F2_3<0b0001, "bpe">; // Branch == + def BPG : F2_3<0b1010, "bpg">; // Branch > + def BPLE : F2_3<0b0010, "bple">; // Branch <= + def BPGE : F2_3<0b1011, "bpge">; // Branch >= + def BPL : F2_3<0b0011, "bpl">; // Branch < + def BPGU : F2_3<0b1100, "bpgu">; // Branch unsigned > + def BPLEU : F2_3<0b0100, "bpleu">; // Branch unsigned <= + def BPCC : F2_3<0b1101, "bpcc">; // Branch unsigned >= + def BPCS : F2_3<0b0101, "bpcs">; // Branch unsigned <= + def BPPOS : F2_3<0b1110, "bppos">; // Branch on positive + def BPNEG : F2_3<0b0110, "bpneg">; // Branch on negative + def BPVC : F2_3<0b1111, "bpvc">; // Branch on overflow clear + def BPVS : F2_3<0b0111, "bpvs">; // Branch on overflow set + } + */ + + // Section A.8: CALL - p151, the only Format #1 instruction + def CALL : InstV9 { + bits<30> disp; + let op = 1; + let Inst{29-0} = disp; + let Name = "call"; + let isCall = 1; + } + + // Section A.9: Compare and Swap - p176 + // CASA/CASXA: are for alternate address spaces! Ignore them + + + // Section A.10: Divide (64-bit / 32-bit) - p178 + // Not used in the SparcV9 backend + /* + let isDeprecated = 1 in { + def UDIVr : F3_1<2, 0b001110, "udiv">; // udiv r, r, r + def UDIVi : F3_2<2, 0b001110, "udiv">; // udiv r, r, i + def SDIVr : F3_1<2, 0b001111, "sdiv">; // sdiv r, r, r + def SDIVi : F3_2<2, 0b001111, "sdiv">; // sdiv r, r, i + def UDIVCCr : F3_1<2, 0b011110, "udivcc">; // udivcc r, r, r + def UDIVCCi : F3_2<2, 0b011110, "udivcc">; // udivcc r, r, i + def SDIVCCr : F3_1<2, 0b011111, "sdivcc">; // sdivcc r, r, r + def SDIVCCi : F3_2<2, 0b011111, "sdivcc">; // sdivcc r, r, i + } + */ + + // Section A.11: DONE and RETRY - p181 + // Not used in the SparcV9 backend + /* + let isPrivileged = 1 in { + def DONE : F3_18<0, "done">; // done + def RETRY : F3_18<1, "retry">; // retry + } + */ + + // Section A.12: Floating-Point Add and Subtract - p156 + def FADDS : F3_16<2, 0b110100, 0x41, "fadds">; // fadds frs1, frs2, frd + def FADDD : F3_16<2, 0b110100, 0x42, "faddd">; // faddd frs1, frs2, frd + def FADDQ : F3_16<2, 0b110100, 0x43, "faddq">; // faddq frs1, frs2, frd + def FSUBS : F3_16<2, 0b110100, 0x45, "fsubs">; // fsubs frs1, frs2, frd + def FSUBD : F3_16<2, 0b110100, 0x46, "fsubd">; // fsubd frs1, frs2, frd + def FSUBQ : F3_16<2, 0b110100, 0x47, "fsubq">; // fsubq frs1, frs2, frd + + // Section A.13: Floating-point compare - p159 + 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 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 + def FCMPEQ : F3_15<2, 0b110101, 0b001010111, "fcmpeq">; // fcmpeq %fcc, r1, r2 + */ + + // Section A.14: Convert floating-point to integer - p161 + def FSTOX : F3_14<2, 0b110100, 0b010000001, "fstox">; // fstox rs2, rd + def FDTOX : F3_14<2, 0b110100, 0b010000010, "fstox">; // fstox rs2, rd + def FQTOX : F3_14<2, 0b110100, 0b010000011, "fstox">; // fstox rs2, rd + def FSTOI : F3_14<2, 0b110100, 0b011010001, "fstoi">; // fstoi rs2, rd + def FDTOI : F3_14<2, 0b110100, 0b011010010, "fdtoi">; // fdtoi rs2, rd + def FQTOI : F3_14<2, 0b110100, 0b011010011, "fqtoi">; // fqtoi rs2, rd + + // Section A.15: Convert between floating-point formats - p162 + def FSTOD : F3_14<2, 0b110100, 0b011001001, "fstod">; // fstod rs2, rd + def FSTOQ : F3_14<2, 0b110100, 0b011001101, "fstoq">; // fstoq rs2, rd + def FDTOS : F3_14<2, 0b110100, 0b011000110, "fstos">; // fstos rs2, rd + def FDTOQ : F3_14<2, 0b110100, 0b011001110, "fdtoq">; // fdtoq rs2, rd + def FQTOS : F3_14<2, 0b110100, 0b011000111, "fqtos">; // fqtos rs2, rd + def FQTOD : F3_14<2, 0b110100, 0b011001011, "fqtod">; // fqtod rs2, rd + + // Section A.16: Convert integer to floating-point - p163 + def FXTOS : F3_14<2, 0b110100, 0b010000100, "fxtos">; // fxtos rs2, rd + def FXTOD : F3_14<2, 0b110100, 0b010001000, "fxtod">; // fxtod rs2, rd + def FXTOQ : F3_14<2, 0b110100, 0b010001100, "fxtoq">; // fxtoq rs2, rd + def FITOS : F3_14<2, 0b110100, 0b011000100, "fitos">; // fitos rs2, rd + def FITOD : F3_14<2, 0b110100, 0b011001000, "fitod">; // fitod rs2, rd + def FITOQ : F3_14<2, 0b110100, 0b011001100, "fitoq">; // fitoq rs2, rd + + // Section A.17: Floating-Point Move - p164 + def FMOVS : F3_14<2, 0b110100, 0b000000001, "fmovs">; // fmovs r, r + def FMOVD : F3_14<2, 0b110100, 0b000000010, "fmovs">; // fmovd r, r + //def FMOVQ : F3_14<2, 0b110100, 0b000000011, "fmovs">; // fmovq r, r + def FNEGS : F3_14<2, 0b110100, 0b000000101, "fnegs">; // fnegs r, r + def FNEGD : F3_14<2, 0b110100, 0b000000110, "fnegs">; // fnegs r, r + //def FNEGQ : F3_14<2, 0b110100, 0b000000111, "fnegs">; // fnegs r, r + def FABSS : F3_14<2, 0b110100, 0b000001001, "fabss">; // fabss r, r + def FABSD : F3_14<2, 0b110100, 0b000001010, "fabss">; // fabss r, r + //def FABSQ : F3_14<2, 0b110100, 0b000001011, "fabss">; // fabss r, r + + // Section A.18: Floating-Point Multiply and Divide - p165 + def FMULS : F3_16<2, 0b110100, 0b001001001, "fmuls">; // fmuls r, r, r + def FMULD : F3_16<2, 0b110100, 0b001001010, "fmuld">; // fmuld r, r, r + def FMULQ : F3_16<2, 0b110100, 0b001001011, "fmulq">; // fmulq r, r, r + def FSMULD : F3_16<2, 0b110100, 0b001101001, "fsmuld">; // fsmuls r, r, r + def FDMULQ : F3_16<2, 0b110100, 0b001101110, "fdmulq">; // fdmuls r, r, r + def FDIVS : F3_16<2, 0b110100, 0b001001101, "fdivs">; // fdivs r, r, r + def FDIVD : F3_16<2, 0b110100, 0b001001110, "fdivs">; // fdivd r, r, r + def FDIVQ : F3_16<2, 0b110100, 0b001001111, "fdivs">; // fdivq r, r, r + + // Section A.19: Floating-Point Square Root - p166 + def FSQRTS : F3_14<2, 0b110100, 0b000101001, "fsqrts">; // fsqrts r, r + def FSQRTD : F3_14<2, 0b110100, 0b000101010, "fsqrts">; // fsqrts r, r + def FSQRTQ : F3_14<2, 0b110100, 0b000101011, "fsqrts">; // fsqrts r, r + + // A.20: Flush Instruction Memory - p167 + // Not currently used + + // A.21: Flush Register Windows - p169 + // Not currently used + + // A.22: Illegal instruction Trap - p170 + // Not currently used + + // A.23: Implementation-Dependent Instructions - p171 + // Not currently used + + // Section A.24: Jump and Link - p172 + // 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 + def JMPLRETi : F3_2<2, 0b111000, "jmpl">; // jmpl [rs1+imm], rd + + // Section A.25: Load Floating-Point - p173 + def LDFr : F3_1<3, 0b100000, "ld">; // ld [rs1+rs2], rd + def LDFi : F3_2<3, 0b100000, "ld">; // ld [rs1+imm], rd + def LDDFr : F3_1<3, 0b100011, "ldd">; // ldd [rs1+rs2], rd + def LDDFi : F3_2<3, 0b100011, "ldd">; // ldd [rs1+imm], rd + def LDQFr : F3_1<3, 0b100010, "ldq">; // ldq [rs1+rs2], rd + def LDQFi : F3_2<3, 0b100010, "ldq">; // ldq [rs1+imm], rd + let isDeprecated = 1 in { + let rd = 0 in { + def LDFSRr : F3_1<3, 0b100001, "ld">; // ld [rs1+rs2], rd + def LDFSRi : F3_2<3, 0b100001, "ld">; // ld [rs1+imm], rd + } + } + let rd = 1 in { + def LDXFSRr : F3_1<3, 0b100001, "ldx">; // ldx [rs1+rs2], rd + def LDXFSRi : F3_2<3, 0b100001, "ldx">; // ldx [rs1+imm], rd + } + + // Section A.27: Load Integer - p178 + def LDSBr : F3_1<3, 0b001001, "ldsb">; // ldsb [rs1+rs2], rd + def LDSBi : F3_2<3, 0b001001, "ldsb">; // ldsb [rs1+imm], rd + def LDSHr : F3_1<3, 0b001010, "ldsh">; // ldsh [rs1+rs2], rd + def LDSHi : F3_2<3, 0b001010, "ldsh">; // ldsh [rs1+imm], rd + def LDSWr : F3_1<3, 0b001000, "ldsw">; // ldsh [rs1+rs2], rd + def LDSWi : F3_2<3, 0b001000, "ldsw">; // ldsh [rs1+imm], rd + def LDUBr : F3_1<3, 0b000001, "ldub">; // ldub [rs1+rs2], rd + def LDUBi : F3_2<3, 0b000001, "ldub">; // ldub [rs1+imm], rd + def LDUHr : F3_1<3, 0b000010, "lduh">; // lduh [rs1+rs2], rd + def LDUHi : F3_2<3, 0b000010, "lduh">; // lduh [rs1+imm], rd + // synonym: LD + def LDUWr : F3_1<3, 0b000000, "lduw">; // lduw [rs1+rs2], rd + def LDUWi : F3_2<3, 0b000000, "lduw">; // lduw [rs1+imm], rd + def LDXr : F3_1<3, 0b001011, "ldx">; // ldx [rs1+rs2], rd + def LDXi : F3_2<3, 0b001011, "ldx">; // ldx [rs1+imm], rd + /* + let isDeprecated = 1 in { + def LDDr : F3_1<3, 0b000011, "ldd">; // ldd [rs1+rs2], rd + def LDDi : F3_2<3, 0b000011, "ldd">; // ldd [rs1+imm], rd + } + */ + + // Section A.31: Logical operations + def ANDr : F3_1<2, 0b000001, "and">; // and rs1, rs2, rd + def ANDi : F3_2<2, 0b000001, "and">; // and rs1, imm, rd + def ANDccr : F3_1<2, 0b010001, "andcc">; // andcc rs1, rs2, rd + def ANDcci : F3_2<2, 0b010001, "andcc">; // andcc rs1, imm, rd + def ANDNr : F3_1<2, 0b000101, "andn">; // andn rs1, rs2, rd + def ANDNi : F3_2<2, 0b000101, "andn">; // andn rs1, imm, rd + def ANDNccr : F3_1<2, 0b010101, "andncc">; // andncc rs1, rs2, rd + def ANDNcci : F3_2<2, 0b010101, "andncc">; // andncc rs1, imm, rd + + def ORr : F3_1<2, 0b000010, "or">; // or rs1, rs2, rd + def ORi : F3_2<2, 0b000010, "or">; // or rs1, imm, rd + def ORccr : F3_1<2, 0b010010, "orcc">; // orcc rs1, rs2, rd + def ORcci : F3_2<2, 0b010010, "orcc">; // orcc rs1, imm, rd + def ORNr : F3_1<2, 0b000110, "orn">; // orn rs1, rs2, rd + def ORNi : F3_2<2, 0b000110, "orn">; // orn rs1, imm, rd + def ORNccr : F3_1<2, 0b010110, "orncc">; // orncc rs1, rs2, rd + def ORNcci : F3_2<2, 0b010110, "orncc">; // orncc rs1, imm, rd + + def XORr : F3_1<2, 0b000011, "xor">; // xor rs1, rs2, rd + def XORi : F3_2<2, 0b000011, "xor">; // xor rs1, imm, rd + def XORccr : F3_1<2, 0b010011, "xorcc">; // xorcc rs1, rs2, rd + def XORcci : F3_2<2, 0b010011, "xorcc">; // xorcc rs1, imm, rd + def XNORr : F3_1<2, 0b000111, "xnor">; // xnor rs1, rs2, rd + def XNORi : F3_2<2, 0b000111, "xnor">; // xnor rs1, imm, rd + def XNORccr : F3_1<2, 0b010111, "xnorcc">; // xnorcc rs1, rs2, rd + def XNORcci : F3_2<2, 0b010111, "xnorcc">; // xnorcc rs1, imm, rd + + // Section A.32: Memory Barrier - p186 + // Not currently used in the SparcV9 backend + + // Section A.33: Move Floating-Point Register on Condition (FMOVcc) + // ======================= Single Floating Point ====================== + // For integer condition codes + def FMOVSA : F4_7<2, 0b110101, 0b1000, 0b000001, "fmovsa">; // fmovsa cc, r, r + def FMOVSN : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovsn">; // fmovsn cc, r, r + def FMOVSNE : F4_7<2, 0b110101, 0b1001, 0b000001, "fmovsne">; // fmovsne cc, r, r + def FMOVSE : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovse">; // fmovse cc, r, r + def FMOVSG : F4_7<2, 0b110101, 0b1010, 0b000001, "fmovsg">; // fmovsg cc, r, r + def FMOVSLE : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovsle">; // fmovsle cc, r, r + def FMOVSGE : F4_7<2, 0b110101, 0b1011, 0b000001, "fmovsge">; // fmovsge cc, r, r + def FMOVSL : F4_7<2, 0b110101, 0b0011, 0b000001, "fmovsl">; // fmovsl cc, r, r + def FMOVSGU : F4_7<2, 0b110101, 0b1100, 0b000001, "fmovsgu">; // fmovsgu cc, r, r + def FMOVSLEU : F4_7<2, 0b110101, 0b0100, 0b000001, "fmovsleu">; // fmovsleu cc, r, r + def FMOVSCC : F4_7<2, 0b110101, 0b1101, 0b000001, "fmovscc">; // fmovscc cc, r, r + def FMOVSCS : F4_7<2, 0b110101, 0b0101, 0b000001, "fmovscs">; // fmovscs cc, r, r + def FMOVSPOS : F4_7<2, 0b110101, 0b1110, 0b000001, "fmovspos">; // fmovspos cc, r, r + def FMOVSNEG : F4_7<2, 0b110101, 0b0110, 0b000001, "fmovsneg">; // fmovsneg cc, r, r + def FMOVSVC : F4_7<2, 0b110101, 0b1111, 0b000001, "fmovsvc">; // fmovsvc cc, r, r + def FMOVSVS : F4_7<2, 0b110101, 0b0111, 0b000001, "fmovsvs">; // fmovsvs cc, r, r + + // For floating-point condition codes + def FMOVSFA : F4_7<2, 0b110101, 0b0100, 0b000001, "fmovsfa">; // fmovsfa cc,r,r + def FMOVSFN : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovsfn">; // fmovsfa cc,r,r + def FMOVSFU : F4_7<2, 0b110101, 0b0111, 0b000001, "fmovsfu">; // fmovsfu cc,r,r + def FMOVSFG : F4_7<2, 0b110101, 0b0110, 0b000001, "fmovsfg">; // fmovsfg cc,r,r + def FMOVSFUG : F4_7<2, 0b110101, 0b0101, 0b000001, "fmovsfug">; // fmovsfug cc,r,r + def FMOVSFL : F4_7<2, 0b110101, 0b0100, 0b000001, "fmovsfl">; // fmovsfl cc,r,r + def FMOVSFUL : F4_7<2, 0b110101, 0b0011, 0b000001, "fmovsful">; // fmovsful cc,r,r + def FMOVSFLG : F4_7<2, 0b110101, 0b0010, 0b000001, "fmovsflg">; // fmovsflg cc,r,r + def FMOVSFNE : F4_7<2, 0b110101, 0b0001, 0b000001, "fmovsfne">; // fmovsfne cc,r,r + def FMOVSFE : F4_7<2, 0b110101, 0b1001, 0b000001, "fmovsfe">; // fmovsfe cc,r,r + def FMOVSFUE : F4_7<2, 0b110101, 0b1010, 0b000001, "fmovsfue">; // fmovsfue cc,r,r + def FMOVSFGE : F4_7<2, 0b110101, 0b1011, 0b000001, "fmovsge">; // fmovsge cc,r,r + def FMOVSFUGE : F4_7<2, 0b110101, 0b1100, 0b000001, "fmovsfuge">;// fmovsfuge cc,r,r + def FMOVSFLE : F4_7<2, 0b110101, 0b1101, 0b000001, "fmovsfle">; // fmovsfle cc,r,r + def FMOVSFULE : F4_7<2, 0b110101, 0b1110, 0b000001, "fmovsfule">;// fmovsfule cc,r,r + def FMOVSFO : F4_7<2, 0b110101, 0b1111, 0b000001, "fmovsfo">; // fmovsfo cc,r,r + + // ======================= Double Floating Point ====================== + // For integer condition codes + def FMOVDA : F4_7<2, 0b110101, 0b1000, 0b000010, "fmovda">; // fmovda cc, r, r + def FMOVDN : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovdn">; // fmovdn cc, r, r + def FMOVDNE : F4_7<2, 0b110101, 0b1001, 0b000010, "fmovdne">; // fmovdne cc, r, r + def FMOVDE : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovde">; // fmovde cc, r, r + def FMOVDG : F4_7<2, 0b110101, 0b1010, 0b000010, "fmovdg">; // fmovdg cc, r, r + def FMOVDLE : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovdle">; // fmovdle cc, r, r + def FMOVDGE : F4_7<2, 0b110101, 0b1011, 0b000010, "fmovdge">; // fmovdge cc, r, r + def FMOVDL : F4_7<2, 0b110101, 0b0011, 0b000010, "fmovdl">; // fmovdl cc, r, r + def FMOVDGU : F4_7<2, 0b110101, 0b1100, 0b000010, "fmovdgu">; // fmovdgu cc, r, r + def FMOVDLEU : F4_7<2, 0b110101, 0b0100, 0b000010, "fmovdleu">; // fmovdleu cc, r, r + def FMOVDCC : F4_7<2, 0b110101, 0b1101, 0b000010, "fmovdcc">; // fmovdcc cc, r, r + def FMOVDCS : F4_7<2, 0b110101, 0b0101, 0b000010, "fmovdcs">; // fmovdcs cc, r, r + def FMOVDPOS : F4_7<2, 0b110101, 0b1110, 0b000010, "fmovdpos">; // fmovdpos cc, r, r + def FMOVDNEG : F4_7<2, 0b110101, 0b0110, 0b000010, "fmovdneg">; // fmovdneg cc, r, r + def FMOVDVC : F4_7<2, 0b110101, 0b1111, 0b000010, "fmovdvc">; // fmovdvc cc, r, r + def FMOVDVS : F4_7<2, 0b110101, 0b0111, 0b000010, "fmovdvs">; // fmovdvs cc, r, r + + // For floating-point condition codes + def FMOVDFA : F4_7<2, 0b110101, 0b0100, 0b000010, "fmovdfa">; // fmovdfa cc,r,r + def FMOVDFN : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovdfn">; // fmovdfa cc,r,r + def FMOVDFU : F4_7<2, 0b110101, 0b0111, 0b000010, "fmovdfu">; // fmovdfu cc,r,r + def FMOVDFG : F4_7<2, 0b110101, 0b0110, 0b000010, "fmovdfg">; // fmovdfg cc,r,r + def FMOVDFUG : F4_7<2, 0b110101, 0b0101, 0b000010, "fmovdfug">; // fmovdfug cc,r,r + def FMOVDFL : F4_7<2, 0b110101, 0b0100, 0b000010, "fmovdfl">; // fmovdfl cc,r,r + def FMOVDFUL : F4_7<2, 0b110101, 0b0011, 0b000010, "fmovdful">; // fmovdful cc,r,r + def FMOVDFLG : F4_7<2, 0b110101, 0b0010, 0b000010, "fmovdflg">; // fmovdflg cc,r,r + def FMOVDFNE : F4_7<2, 0b110101, 0b0001, 0b000010, "fmovdfne">; // fmovdfne cc,r,r + def FMOVDFE : F4_7<2, 0b110101, 0b1001, 0b000010, "fmovdfe">; // fmovdfe cc,r,r + def FMOVDFUE : F4_7<2, 0b110101, 0b1010, 0b000010, "fmovdfue">; // fmovdfue cc,r,r + def FMOVDFGE : F4_7<2, 0b110101, 0b1011, 0b000010, "fmovdge">; // fmovdge cc,r,r + def FMOVDFUGE : F4_7<2, 0b110101, 0b1100, 0b000010, "fmovdfuge">;// fmovdfuge cc,r,r + def FMOVDFLE : F4_7<2, 0b110101, 0b1101, 0b000010, "fmovdfle">; // fmovdfle cc,r,r + def FMOVDFULE : F4_7<2, 0b110101, 0b1110, 0b000010, "fmovdfule">;// fmovdfule cc,r,r + def FMOVDFO : F4_7<2, 0b110101, 0b1111, 0b000010, "fmovdfo">; // fmovdfo cc,r,r + + // ======================= Quad Floating Point ====================== + // For integer condition codes + def FMOVQA : F4_7<2, 0b110101, 0b1000, 0b000011, "fmovqa">; // fmovqa cc, r, r + def FMOVQN : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqn">; // fmovqn cc, r, r + def FMOVQNE : F4_7<2, 0b110101, 0b1001, 0b000011, "fmovqne">; // fmovqne cc, r, r + def FMOVQE : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqe">; // fmovqe cc, r, r + def FMOVQG : F4_7<2, 0b110101, 0b1010, 0b000011, "fmovqg">; // fmovqg cc, r, r + def FMOVQLE : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqle">; // fmovqle cc, r, r + def FMOVQGE : F4_7<2, 0b110101, 0b1011, 0b000011, "fmovqge">; // fmovqge cc, r, r + def FMOVQL : F4_7<2, 0b110101, 0b0011, 0b000011, "fmovql">; // fmovql cc, r, r + def FMOVQGU : F4_7<2, 0b110101, 0b1100, 0b000011, "fmovqgu">; // fmovqgu cc, r, r + def FMOVQLEU : F4_7<2, 0b110101, 0b0100, 0b000011, "fmovqleu">; // fmovqleu cc, r, r + def FMOVQCC : F4_7<2, 0b110101, 0b1101, 0b000011, "fmovqcc">; // fmovqcc cc, r, r + def FMOVQCS : F4_7<2, 0b110101, 0b0101, 0b000011, "fmovqcs">; // fmovqcs cc, r, r + def FMOVQPOS : F4_7<2, 0b110101, 0b1110, 0b000011, "fmovqpos">; // fmovqpos cc, r, r + def FMOVQNEG : F4_7<2, 0b110101, 0b0110, 0b000011, "fmovqneg">; // fmovqneg cc, r, r + def FMOVQVC : F4_7<2, 0b110101, 0b1111, 0b000011, "fmovqvc">; // fmovqvc cc, r, r + def FMOVQVS : F4_7<2, 0b110101, 0b0111, 0b000011, "fmovqvs">; // fmovqvs cc, r, r + + // For floating-point condition codes + def FMOVQFA : F4_7<2, 0b110101, 0b0100, 0b000011, "fmovqfa">; // fmovqfa cc,r,r + def FMOVQFN : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqfn">; // fmovqfa cc,r,r + def FMOVQFU : F4_7<2, 0b110101, 0b0111, 0b000011, "fmovqfu">; // fmovqfu cc,r,r + def FMOVQFG : F4_7<2, 0b110101, 0b0110, 0b000011, "fmovqfg">; // fmovqfg cc,r,r + def FMOVQFUG : F4_7<2, 0b110101, 0b0101, 0b000011, "fmovqfug">; // fmovqfug cc,r,r + def FMOVQFL : F4_7<2, 0b110101, 0b0100, 0b000011, "fmovqfl">; // fmovqfl cc,r,r + def FMOVQFUL : F4_7<2, 0b110101, 0b0011, 0b000011, "fmovqful">; // fmovqful cc,r,r + def FMOVQFLG : F4_7<2, 0b110101, 0b0010, 0b000011, "fmovqflg">; // fmovqflg cc,r,r + def FMOVQFNE : F4_7<2, 0b110101, 0b0001, 0b000011, "fmovqfne">; // fmovqfne cc,r,r + def FMOVQFE : F4_7<2, 0b110101, 0b1001, 0b000011, "fmovqfe">; // fmovqfe cc,r,r + def FMOVQFUE : F4_7<2, 0b110101, 0b1010, 0b000011, "fmovqfue">; // fmovqfue cc,r,r + def FMOVQFGE : F4_7<2, 0b110101, 0b1011, 0b000011, "fmovqge">; // fmovqge cc,r,r + def FMOVQFUGE : F4_7<2, 0b110101, 0b1100, 0b000011, "fmovqfuge">;// fmovqfuge cc,r,r + def FMOVQFLE : F4_7<2, 0b110101, 0b1101, 0b000011, "fmovqfle">; // fmovqfle cc,r,r + def FMOVQFULE : F4_7<2, 0b110101, 0b1110, 0b000011, "fmovqfule">;// fmovqfule cc,r,r + def FMOVQFO : F4_7<2, 0b110101, 0b1111, 0b000011, "fmovqfo">; // fmovqfo cc,r,r + + // Section A.34: Move FP Register on Integer Register condition (FMOVr) - p192 + def FMOVRSZ : F4_6<2, 0b110101, 0b001, 0b00101, "fmovrsz">; //fmovsrz r,r,rd + def FMOVRSLEZ : F4_6<2, 0b110101, 0b010, 0b00101, "fmovrslez">;//fmovsrz r,r,rd + def FMOVRSLZ : F4_6<2, 0b110101, 0b011, 0b00101, "fmovrslz">; //fmovsrz r,r,rd + def FMOVRSNZ : F4_6<2, 0b110101, 0b101, 0b00101, "fmovrsne">; //fmovsrz r,r,rd + def FMOVRSGZ : F4_6<2, 0b110101, 0b110, 0b00101, "fmovrsgz">; //fmovsrz r,r,rd + def FMOVRSGEZ : F4_6<2, 0b110101, 0b111, 0b00101, "fmovrsgez">;//fmovsrz r,r,rd + + def FMOVRDZ : F4_6<2, 0b110101, 0b001, 0b00110, "fmovrdz">; //fmovsrz r,r,rd + def FMOVRDLEZ : F4_6<2, 0b110101, 0b010, 0b00110, "fmovrdlez">;//fmovsrz r,r,rd + def FMOVRDLZ : F4_6<2, 0b110101, 0b011, 0b00110, "fmovrdlz">; //fmovsrz r,r,rd + def FMOVRDNZ : F4_6<2, 0b110101, 0b101, 0b00110, "fmovrdne">; //fmovsrz r,r,rd + def FMOVRDGZ : F4_6<2, 0b110101, 0b110, 0b00110, "fmovrdgz">; //fmovsrz r,r,rd + def FMOVRDGEZ : F4_6<2, 0b110101, 0b111, 0b00110, "fmovrdgez">;//fmovsrz r,r,rd + + def FMOVRQZ : F4_6<2, 0b110101, 0b001, 0b00111, "fmovrqz">; //fmovsrz r,r,rd + def FMOVRQLEZ : F4_6<2, 0b110101, 0b010, 0b00111, "fmovrqlez">;//fmovsrz r,r,rd + def FMOVRQLZ : F4_6<2, 0b110101, 0b011, 0b00111, "fmovrqlz">; //fmovsrz r,r,rd + def FMOVRQNZ : F4_6<2, 0b110101, 0b101, 0b00111, "fmovrqne">; //fmovsrz r,r,rd + def FMOVRQGZ : F4_6<2, 0b110101, 0b110, 0b00111, "fmovrqgz">; //fmovsrz r,r,rd + def FMOVRQGEZ : F4_6<2, 0b110101, 0b111, 0b00111, "fmovrqgez">;//fmovsrz r,r,rd + + + // Section A.35: Move Integer Register on Condition (MOVcc) - p194 + // For integer condition codes + def MOVAr : F4_3<2, 0b101100, 0b1000, "mova">; // mova i/xcc, rs2, rd + def MOVAi : F4_4<2, 0b101100, 0b1000, "mova">; // mova i/xcc, imm, rd + def MOVNr : F4_3<2, 0b101100, 0b0000, "movn">; // movn i/xcc, rs2, rd + def MOVNi : F4_4<2, 0b101100, 0b0000, "movn">; // movn i/xcc, imm, rd + def MOVNEr : F4_3<2, 0b101100, 0b1001, "movne">; // movne i/xcc, rs2, rd + def MOVNEi : F4_4<2, 0b101100, 0b1001, "movne">; // movne i/xcc, imm, rd + def MOVEr : F4_3<2, 0b101100, 0b0001, "move">; // move i/xcc, rs2, rd + def MOVEi : F4_4<2, 0b101100, 0b0001, "move">; // move i/xcc, imm, rd + def MOVGr : F4_3<2, 0b101100, 0b1010, "movg">; // movg i/xcc, rs2, rd + def MOVGi : F4_4<2, 0b101100, 0b1010, "movg">; // movg i/xcc, imm, rd + def MOVLEr : F4_3<2, 0b101100, 0b0010, "movle">; // movle i/xcc, rs2, rd + def MOVLEi : F4_4<2, 0b101100, 0b0010, "movle">; // movle i/xcc, imm, rd + def MOVGEr : F4_3<2, 0b101100, 0b1011, "movge">; // movge i/xcc, rs2, rd + def MOVGEi : F4_4<2, 0b101100, 0b1011, "movge">; // movge i/xcc, imm, rd + def MOVLr : F4_3<2, 0b101100, 0b0011, "movl">; // movl i/xcc, rs2, rd + def MOVLi : F4_4<2, 0b101100, 0b0011, "movl">; // movl i/xcc, imm, rd + def MOVGUr : F4_3<2, 0b101100, 0b1100, "movgu">; // movgu i/xcc, rs2, rd + def MOVGUi : F4_4<2, 0b101100, 0b1100, "movgu">; // movgu i/xcc, imm, rd + def MOVLEUr : F4_3<2, 0b101100, 0b0100, "movleu">; // movleu i/xcc, rs2, rd + def MOVLEUi : F4_4<2, 0b101100, 0b0100, "movleu">; // movleu i/xcc, imm, rd + def MOVCCr : F4_3<2, 0b101100, 0b1101, "movcc">; // movcc i/xcc, rs2, rd + def MOVCCi : F4_4<2, 0b101100, 0b1101, "movcc">; // movcc i/xcc, imm, rd + def MOVCSr : F4_3<2, 0b101100, 0b0101, "movcs">; // movcs i/xcc, rs2, rd + def MOVCSi : F4_4<2, 0b101100, 0b0101, "movcs">; // movcs i/xcc, imm, rd + def MOVPOSr : F4_3<2, 0b101100, 0b1110, "movpos">; // movpos i/xcc, rs2, rd + def MOVPOSi : F4_4<2, 0b101100, 0b1110, "movpos">; // movpos i/xcc, imm, rd + def MOVNEGr : F4_3<2, 0b101100, 0b0110, "movneg">; // movneg i/xcc, rs2, rd + def MOVNEGi : F4_4<2, 0b101100, 0b0110, "movneg">; // movneg i/xcc, imm, rd + def MOVVCr : F4_3<2, 0b101100, 0b1111, "movvc">; // movvc i/xcc, rs2, rd + def MOVVCi : F4_4<2, 0b101100, 0b1111, "movvc">; // movvc i/xcc, imm, rd + def MOVVSr : F4_3<2, 0b101100, 0b0111, "movvs">; // movvs i/xcc, rs2, rd + def MOVVSi : F4_4<2, 0b101100, 0b0111, "movvs">; // movvs i/xcc, imm, rd + + // For floating-point condition codes + def MOVFAr : F4_3<2, 0b101100, 0b1000, "movfa">; // movfa i/xcc, rs2, rd + def MOVFAi : F4_4<2, 0b101100, 0b1000, "movfa">; // movfa i/xcc, imm, rd + def MOVFNr : F4_3<2, 0b101100, 0b0000, "movfn">; // movfn i/xcc, rs2, rd + def MOVFNi : F4_4<2, 0b101100, 0b0000, "movfn">; // movfn i/xcc, imm, rd + def MOVFUr : F4_3<2, 0b101100, 0b0111, "movfu">; // movfu i/xcc, rs2, rd + def MOVFUi : F4_4<2, 0b101100, 0b0111, "movfu">; // movfu i/xcc, imm, rd + def MOVFGr : F4_3<2, 0b101100, 0b0110, "movfg">; // movfg i/xcc, rs2, rd + def MOVFGi : F4_4<2, 0b101100, 0b0110, "movfg">; // movfg i/xcc, imm, rd + def MOVFUGr : F4_3<2, 0b101100, 0b0101, "movfug">; // movfug i/xcc, rs2, rd + def MOVFUGi : F4_4<2, 0b101100, 0b0101, "movfug">; // movfug i/xcc, imm, rd + def MOVFLr : F4_3<2, 0b101100, 0b0100, "movfl">; // movfl i/xcc, rs2, rd + def MOVFLi : F4_4<2, 0b101100, 0b0100, "movfl">; // movfl i/xcc, imm, rd + def MOVFULr : F4_3<2, 0b101100, 0b0011, "movful">; // movful i/xcc, rs2, rd + def MOVFULi : F4_4<2, 0b101100, 0b0011, "movful">; // movful i/xcc, imm, rd + def MOVFLGr : F4_3<2, 0b101100, 0b0010, "movflg">; // movflg i/xcc, rs2, rd + def MOVFLGi : F4_4<2, 0b101100, 0b0010, "movflg">; // movflg i/xcc, imm, rd + def MOVFNEr : F4_3<2, 0b101100, 0b0001, "movfne">; // movfne i/xcc, rs2, rd + def MOVFNEi : F4_4<2, 0b101100, 0b0001, "movfne">; // movfne i/xcc, imm, rd + def MOVFEr : F4_3<2, 0b101100, 0b1001, "movfe">; // movfe i/xcc, rs2, rd + def MOVFEi : F4_4<2, 0b101100, 0b1001, "movfe">; // movfe i/xcc, imm, rd + def MOVFUEr : F4_3<2, 0b101100, 0b1010, "movfue">; // movfue i/xcc, rs2, rd + def MOVFUEi : F4_4<2, 0b101100, 0b1010, "movfue">; // movfue i/xcc, imm, rd + def MOVFGEr : F4_3<2, 0b101100, 0b1011, "movfge">; // movfge i/xcc, rs2, rd + def MOVFGEi : F4_4<2, 0b101100, 0b1011, "movfge">; // movfge i/xcc, imm, rd + def MOVFUGEr : F4_3<2, 0b101100, 0b1100, "movfuge">; // movfuge i/xcc, rs2, rd + def MOVFUGEi : F4_4<2, 0b101100, 0b1100, "movfuge">; // movfuge i/xcc, imm, rd + def MOVFLEr : F4_3<2, 0b101100, 0b1101, "movfle">; // movfle i/xcc, rs2, rd + def MOVFLEi : F4_4<2, 0b101100, 0b1101, "movfle">; // movfle i/xcc, imm, rd + def MOVFULEr : F4_3<2, 0b101100, 0b1110, "movfule">; // movfule i/xcc, rs2, rd + def MOVFULEi : F4_4<2, 0b101100, 0b1110, "movfule">; // movfule i/xcc, imm, rd + def MOVFOr : F4_3<2, 0b101100, 0b1111, "movfo">; // movfo i/xcc, rs2, rd + def MOVFOi : F4_4<2, 0b101100, 0b1111, "movfo">; // movfo i/xcc, imm, rd + + // Section A.36: Move Integer Register on Register Condition (MOVR) - p198 + def MOVRZr : F3_5<2, 0b101111, 0b001, "movrz">; // movrz rs1, rs2, rd + def MOVRZi : F3_6<2, 0b101111, 0b001, "movrz">; // movrz rs1, imm, rd + def MOVRLEZr : F3_5<2, 0b101111, 0b010, "movrlez">; // movrlez rs1, rs2, rd + def MOVRLEZi : F3_6<2, 0b101111, 0b010, "movrlez">; // movrlez rs1, imm, rd + def MOVRLZr : F3_5<2, 0b101111, 0b011, "movrlz">; // movrlz rs1, rs2, rd + def MOVRLZi : F3_6<2, 0b101111, 0b011, "movrlz">; // movrlz rs1, imm, rd + def MOVRNZr : F3_5<2, 0b101111, 0b101, "movrnz">; // movrnz rs1, rs2, rd + def MOVRNZi : F3_6<2, 0b101111, 0b101, "movrnz">; // movrnz rs1, imm, rd + def MOVRGZr : F3_5<2, 0b101111, 0b110, "movrgz">; // movrgz rs1, rs2, rd + def MOVRGZi : F3_6<2, 0b101111, 0b110, "movrgz">; // movrgz rs1, imm, rd + def MOVRGEZr : F3_5<2, 0b101111, 0b111, "movrgez">; // movrgez rs1, rs2, rd + def MOVRGEZi : F3_6<2, 0b101111, 0b111, "movrgez">; // movrgez rs1, imm, rd + + // Section A.37: Multiply and Divide (64-bit) - p199 + def MULXr : F3_1<2, 0b001001, "mulx">; // mulx r, r, r + def MULXi : F3_2<2, 0b001001, "mulx">; // mulx r, i, r + def SDIVXr : F3_1<2, 0b101101, "sdivx">; // sdivx r, r, r + def SDIVXi : F3_2<2, 0b101101, "sdivx">; // sdivx r, i, r + def UDIVXr : F3_1<2, 0b001101, "udivx">; // udivx r, r, r + def UDIVXi : F3_2<2, 0b001101, "udivx">; // udivx r, i, r + + // Section A.38: Multiply (32-bit) - p200 + // Not used in the SparcV9 backend + /* + let Inst{13} = 0 in { + def UMULr : F3_1<2, 0b001010, "umul">; // umul r, r, r + def SMULr : F3_1<2, 0b001011, "smul">; // smul r, r, r + def UMULCCr : F3_1<2, 0b011010, "umulcc">; // mulcc r, r, r + def SMULCCr : F3_1<2, 0b011011, "smulcc">; // smulcc r, r, r + } + let Inst{13} = 1 in { + def UMULi : F3_1<2, 0b001010, "umul">; // umul r, i, r + def SMULi : F3_1<2, 0b001011, "smul">; // smul r, i, r + def UMULCCi : F3_1<2, 0b011010, "umulcc">; // umulcc r, i, r + def SMULCCi : F3_1<2, 0b011011, "smulcc">; // smulcc r, i, r + } + */ + + // Section A.39: Multiply Step - p202 + // Not currently used in the SparcV9 backend + + // Section A.40: No operation - p204 + // NOP is really a pseudo-instruction (special case of SETHI) + let op2 = 0b100 in { + let rd = 0 in { + let imm = 0 in { + def NOP : F2_1<"nop">; // nop + } + } + } + + // Section A.41: Population Count - p205 + // Not currently used in the SparcV9 backend + + // Section A.42: Prefetch Data - p206 + // Not currently used in the SparcV9 backend + + // Section A.43: Read Privileged Register - p211 + // Not currently used in the SparcV9 backend + + // Section A.44: Read State Register + // The only instr from this section currently used is RDCCR + let rs1 = 2 in { + def RDCCR : F3_17<2, 0b101000, "rd">; // rd %ccr, r + } + + // Section A.46: SAVE and RESTORE - p217 + 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 A.47: SAVED and RESTORED - p219 + // Not currently used in SparcV9 backend + + // Section A.48: SETHI - p220 + let op2 = 0b100 in { + def SETHI : F2_1<"sethi">; // sethi + } + + // Section A.49: Shift - p221 + // Not currently used in the SparcV9 backend + /* + uses 5 least significant bits of rs2 + let x = 0 in { + def SLLr5 : F3_11<2, 0b100101, "sll">; // sll r, r, r + def SRLr5 : F3_11<2, 0b100110, "srl">; // srl r, r, r + def SRAr5 : F3_11<2, 0b100111, "sra">; // sra r, r, r + def SLLXr5 : F3_11<2, 0b100101, "sllx">; // sllx r, r, r + def SRLXr5 : F3_11<2, 0b100110, "srlx">; // srlx r, r, r + def SRAXr5 : F3_11<2, 0b100111, "srax">; // srax r, r, r + } + */ + + // uses 6 least significant bits of rs2 + let x = 0 in { + def SLLr5 : F3_11<2, 0b100101, "sll">; // sll r, r, r + def SRLr5 : F3_11<2, 0b100110, "srl">; // srl r, r, r + def SRAr5 : F3_11<2, 0b100111, "sra">; // sra r, r, r + } + let x = 1 in { + def SLLXr6 : F3_11<2, 0b100101, "sllx">; // sllx r, r, r + def SRLXr6 : F3_11<2, 0b100110, "srlx">; // srlx r, r, r + def SRAXr6 : F3_11<2, 0b100111, "srax">; // srax r, r, r + } + + def SLLi5 : F3_12<2, 0b100101, "sll">; // sll r, shcnt32, r + def SRLi5 : F3_12<2, 0b100110, "srl">; // srl r, shcnt32, r + def SRAi5 : F3_12<2, 0b100111, "sra">; // sra r, shcnt32, r + def SLLXi6 : F3_13<2, 0b100101, "sllx">; // sllx r, shcnt64, r + def SRLXi6 : F3_13<2, 0b100110, "srlx">; // srlx r, shcnt64, r + def SRAXi6 : F3_13<2, 0b100111, "srax">; // srax r, shcnt64, r + + // Section A.50: Sofware-Initiated Reset - p223 + // Not currently used in the SparcV9 backend + + // Section A.51: Store Barrier - p224 + // Not currently used in the SparcV9 backend + + // Section A.52: Store Floating-point - p225 + // Store instructions all want their rd register first + def STFr : F3_1rd<3, 0b100100, "st">; // st r, [r+r] + def STFi : F3_2rd<3, 0b100100, "st">; // st r, [r+i] + 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 SparcV9 backend + /* + def STQFr : F3_1rd<3, 0b100110, "stq">; // stq r, [r+r] + def STQFi : F3_2rd<3, 0b100110, "stq">; // stq r, [r+i] + */ + + // WARNING: We encode %fsr as 1, because we only use STXFSRx, but STFSRx wants + // you to encode %fsr as 0. If STFSRx instrs are ever enabled, this will + // need to be worked around. + /* + let isDeprecated = 1 in { + def STFSRr : F3_1rd<3, 0b100101, "st">; // st %fsr, [r+r] + def STFSRi : F3_2rd<3, 0b100101, "st">; // st %fsr, [r+i] + } + */ + def STXFSRr : F3_1rd<3, 0b100101, "stx">; // stx %fsr, [r+r] + def STXFSRi : F3_2rd<3, 0b100101, "stx">; // stx %fsr, [r+i] + + // Section A.53: Store Floating-Point into Alternate Space - p227 + // Not currently used in the SparcV9 backend + + // Section A.54: Store Integer - p229 + // Store instructions all want their rd register first + def STBr : F3_1rd<3, 0b000101, "stb">; // stb r, [r+r] + def STBi : F3_2rd<3, 0b000101, "stb">; // stb r, [r+i] + def STHr : F3_1rd<3, 0b000110, "sth">; // sth r, [r+r] + def STHi : F3_2rd<3, 0b000110, "sth">; // sth r, [r+i] + def STWr : F3_1rd<3, 0b000100, "stw">; // stw r, [r+r] + def STWi : F3_2rd<3, 0b000100, "stw">; // stw r, [r+i] + def STXr : F3_1rd<3, 0b001110, "stx">; // stx r, [r+r] + 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 SparcV9 backend + + // Section A.56: Subtract - p233 + def SUBr : F3_1<2, 0b000100, "sub">; // sub r, r, r + def SUBi : F3_2<2, 0b000100, "sub">; // sub r, i, r + def SUBccr : F3_1<2, 0b010100, "subcc">; // subcc r, r, r + def SUBcci : F3_2<2, 0b010100, "subcc">; // subcc r, i, r + def SUBCr : F3_1<2, 0b001100, "subc">; // subc r, r, r + def SUBCi : F3_2<2, 0b001100, "subc">; // subc r, i, r + def SUBCccr : F3_1<2, 0b011100, "subccc">; // subccc r, r, r + def SUBCcci : F3_2<2, 0b011100, "subccc">; // subccc r, i, r + + // FIXME: More...? + + // Section A.63: Write State Register - p244 + let rd = 2 in { + def WRCCRr : F3_1<2, 0b110000, "wr">; // wr r, r, %y/ccr/etc + def WRCCRi : F3_2<2, 0b110000, "wr">; // wr r, i, %y/ccr/etc + } Index: llvm/lib/Target/SparcV9/SparcV9.td diff -u llvm/lib/Target/SparcV9/SparcV9.td:1.36 llvm/lib/Target/SparcV9/SparcV9.td:1.37 --- llvm/lib/Target/SparcV9/SparcV9.td:1.36 Tue Aug 10 10:29:15 2004 +++ llvm/lib/Target/SparcV9/SparcV9.td Tue Aug 10 13:15:31 2004 @@ -1,4 +1,4 @@ -//===- SparcV9.td - Target Description for SparcV9 Target -----------------===// +//===- SparcV9.td - Target Description for SparcV9 Target --*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -12,771 +12,43 @@ // //===----------------------------------------------------------------------===// -include "../Target.td" - -include "SparcV9_Reg.td" - //===----------------------------------------------------------------------===// -// Instructions +// Target-independent interfaces which we are implementing //===----------------------------------------------------------------------===// -class InstV9 : Instruction { // SparcV9 instruction baseline - field bits<32> Inst; - - let Name = "SparcV9"; - let Namespace = "V9"; - - bits<2> op; - let Inst{31-30} = op; // Top two bits are the 'op' field - - // 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? -} - -include "SparcV9_F2.td" -include "SparcV9_F3.td" -include "SparcV9_F4.td" +include "../Target.td" //===----------------------------------------------------------------------===// -// Instruction list... -// - -// Section A.2: Add - p137 -def ADDr : F3_1<2, 0b000000, "add">; // add rs1, rs2, rd -def ADDi : F3_2<2, 0b000000, "add">; // add rs1, imm, rd -def ADDccr : F3_1<2, 0b010000, "addcc">; // addcc rs1, rs2, rd -def ADDcci : F3_2<2, 0b010000, "addcc">; // addcc rs1, imm, rd -def ADDCr : F3_1<2, 0b001000, "addC">; // addC rs1, rs2, rd -def ADDCi : F3_2<2, 0b001000, "addC">; // addC rs1, imm, rd -def ADDCccr : F3_1<2, 0b011000, "addCcc">; // addCcc rs1, rs2, rd -def ADDCcci : F3_2<2, 0b011000, "addCcc">; // addCcc rs1, imm, rd - -// Section A.3: Branch on Integer Register with Prediction - p138 -let op2 = 0b011 in { - def BRZ : F2_4<0b001, "brz">; // Branch on rs1 == 0 - def BRLEZ : F2_4<0b010, "brlez">; // Branch on rs1 <= 0 - def BRLZ : F2_4<0b011, "brlz">; // Branch on rs1 < 0 - def BRNZ : F2_4<0b101, "brnz">; // Branch on rs1 != 0 - def BRGZ : F2_4<0b110, "brgz">; // Branch on rs1 > 0 - def BRGEZ : F2_4<0b111, "brgez">; // Branch on rs1 >= 0 -} - -// Section A.4: Branch on Floating-Point Condition Codes (FBfcc) p140 -// The following deprecated instructions don't seem to play nice on SparcV9 -/* -let isDeprecated = 1 in { - let op2 = 0b110 in { - def FBA : F2_2<0b1000, "fba">; // Branch always - def FBN : F2_2<0b0000, "fbn">; // Branch never - def FBU : F2_2<0b0111, "fbu">; // Branch on unordered - def FBG : F2_2<0b0110, "fbg">; // Branch > - def FBUG : F2_2<0b0101, "fbug">; // Branch on unordered or > - def FBL : F2_2<0b0100, "fbl">; // Branch < - def FBUL : F2_2<0b0011, "fbul">; // Branch on unordered or < - def FBLG : F2_2<0b0010, "fblg">; // Branch < or > - def FBNE : F2_2<0b0001, "fbne">; // Branch != - def FBE : F2_2<0b1001, "fbe">; // Branch == - def FBUE : F2_2<0b1010, "fbue">; // Branch on unordered or == - def FBGE : F2_2<0b1011, "fbge">; // Branch > or == - def FBUGE : F2_2<0b1100, "fbuge">; // Branch unord or > or == - def FBLE : F2_2<0b1101, "fble">; // Branch < or == - def FBULE : F2_2<0b1110, "fbule">; // Branch unord or < or == - def FBO : F2_2<0b1111, "fbo">; // Branch on ordered - } -} -*/ - -// We now make these same opcodes represent the FBPfcc instructions -let op2 = 0b101 in { - def FBA : F2_3<0b1000, "fba">; // Branch always - def FBN : F2_3<0b0000, "fbn">; // Branch never - def FBU : F2_3<0b0111, "fbu">; // Branch on unordered - def FBG : F2_3<0b0110, "fbg">; // Branch > - def FBUG : F2_3<0b0101, "fbug">; // Branch on unordered or > - def FBL : F2_3<0b0100, "fbl">; // Branch < - def FBUL : F2_3<0b0011, "fbul">; // Branch on unordered or < - def FBLG : F2_3<0b0010, "fblg">; // Branch < or > - def FBNE : F2_3<0b0001, "fbne">; // Branch != - def FBE : F2_3<0b1001, "fbe">; // Branch == - def FBUE : F2_3<0b1010, "fbue">; // Branch on unordered or == - def FBGE : F2_3<0b1011, "fbge">; // Branch > or == - def FBUGE : F2_3<0b1100, "fbuge">; // Branch unord or > or == - def FBLE : F2_3<0b1101, "fble">; // Branch < or == - def FBULE : F2_3<0b1110, "fbule">; // Branch unord or < or == - def FBO : F2_3<0b1111, "fbo">; // Branch on ordered -} - -// Section A.5: Branch on FP condition codes with prediction - p143 -// Not used in the SparcV9 backend (directly) -/* -let op2 = 0b101 in { - def FBPA : F2_3<0b1000, "fba">; // Branch always - def FBPN : F2_3<0b0000, "fbn">; // Branch never - def FBPU : F2_3<0b0111, "fbu">; // Branch on unordered - def FBPG : F2_3<0b0110, "fbg">; // Branch > - def FBPUG : F2_3<0b0101, "fbug">; // Branch on unordered or > - def FBPL : F2_3<0b0100, "fbl">; // Branch < - def FBPUL : F2_3<0b0011, "fbul">; // Branch on unordered or < - def FBPLG : F2_3<0b0010, "fblg">; // Branch < or > - def FBPNE : F2_3<0b0001, "fbne">; // Branch != - def FBPE : F2_3<0b1001, "fbe">; // Branch == - def FBPUE : F2_3<0b1010, "fbue">; // Branch on unordered or == - def FBPGE : F2_3<0b1011, "fbge">; // Branch > or == - def FBPUGE : F2_3<0b1100, "fbuge">; // Branch unord or > or == - def FBPLE : F2_3<0b1101, "fble">; // Branch < or == - def FBPULE : F2_3<0b1110, "fbule">; // Branch unord or < or == - def FBPO : F2_3<0b1111, "fbo">; // Branch on ordered -} -*/ - -// Section A.6: Branch on Integer condition codes (Bicc) - p146 -/* -let isDeprecated = 1 in { - let op2 = 0b010 in { - def BA : F2_2<0b1000, "ba">; // Branch always - def BN : F2_2<0b0000, "bn">; // Branch never - def BNE : F2_2<0b1001, "bne">; // Branch != - def BE : F2_2<0b0001, "be">; // Branch == - def BG : F2_2<0b1010, "bg">; // Branch > - def BLE : F2_2<0b0010, "ble">; // Branch <= - def BGE : F2_2<0b1011, "bge">; // Branch >= - def BL : F2_2<0b0011, "bl">; // Branch < - def BGU : F2_2<0b1100, "bgu">; // Branch unsigned > - def BLEU : F2_2<0b0100, "bleu">; // Branch unsigned <= - def BCC : F2_2<0b1101, "bcc">; // Branch unsigned >= - def BCS : F2_2<0b0101, "bcs">; // Branch unsigned <= - def BPOS : F2_2<0b1110, "bpos">; // Branch on positive - def BNEG : F2_2<0b0110, "bneg">; // Branch on negative - def BVC : F2_2<0b1111, "bvc">; // Branch on overflow clear - def BVS : F2_2<0b0111, "bvs">; // Branch on overflow set - } -} -*/ - -// Using the format of A.7 instructions... -let op2 = 0b001 in { - let cc = 0 in { // BA and BN don't read condition codes - def BA : F2_3<0b1000, "ba">; // Branch always - def BN : F2_3<0b0000, "bn">; // Branch never - } - def BNE : F2_3<0b1001, "bne">; // Branch != - def BE : F2_3<0b0001, "be">; // Branch == - def BG : F2_3<0b1010, "bg">; // Branch > - def BLE : F2_3<0b0010, "ble">; // Branch <= - def BGE : F2_3<0b1011, "bge">; // Branch >= - def BL : F2_3<0b0011, "bl">; // Branch < - def BGU : F2_3<0b1100, "bgu">; // Branch unsigned > - def BLEU : F2_3<0b0100, "bleu">; // Branch unsigned <= - def BCC : F2_3<0b1101, "bcc">; // Branch unsigned >= - def BCS : F2_3<0b0101, "bcs">; // Branch unsigned <= - def BPOS : F2_3<0b1110, "bpos">; // Branch on positive - def BNEG : F2_3<0b0110, "bneg">; // Branch on negative - def BVC : F2_3<0b1111, "bvc">; // Branch on overflow clear - def BVS : F2_3<0b0111, "bvs">; // Branch on overflow set -} - -// Section A.7: Branch on integer condition codes with prediction - p148 -// Not used in the SparcV9 backend -/* -let op2 = 0b001 in { - def BPA : F2_3<0b1000, "bpa">; // Branch always - def BPN : F2_3<0b0000, "bpn">; // Branch never - def BPNE : F2_3<0b1001, "bpne">; // Branch != - def BPE : F2_3<0b0001, "bpe">; // Branch == - def BPG : F2_3<0b1010, "bpg">; // Branch > - def BPLE : F2_3<0b0010, "bple">; // Branch <= - def BPGE : F2_3<0b1011, "bpge">; // Branch >= - def BPL : F2_3<0b0011, "bpl">; // Branch < - def BPGU : F2_3<0b1100, "bpgu">; // Branch unsigned > - def BPLEU : F2_3<0b0100, "bpleu">; // Branch unsigned <= - def BPCC : F2_3<0b1101, "bpcc">; // Branch unsigned >= - def BPCS : F2_3<0b0101, "bpcs">; // Branch unsigned <= - def BPPOS : F2_3<0b1110, "bppos">; // Branch on positive - def BPNEG : F2_3<0b0110, "bpneg">; // Branch on negative - def BPVC : F2_3<0b1111, "bpvc">; // Branch on overflow clear - def BPVS : F2_3<0b0111, "bpvs">; // Branch on overflow set -} -*/ - -// Section A.8: CALL - p151, the only Format #1 instruction -def CALL : InstV9 { - bits<30> disp; - let op = 1; - let Inst{29-0} = disp; - let Name = "call"; - let isCall = 1; -} - -// Section A.9: Compare and Swap - p176 -// CASA/CASXA: are for alternate address spaces! Ignore them - - -// Section A.10: Divide (64-bit / 32-bit) - p178 -// Not used in the SparcV9 backend -/* -let isDeprecated = 1 in { - def UDIVr : F3_1<2, 0b001110, "udiv">; // udiv r, r, r - def UDIVi : F3_2<2, 0b001110, "udiv">; // udiv r, r, i - def SDIVr : F3_1<2, 0b001111, "sdiv">; // sdiv r, r, r - def SDIVi : F3_2<2, 0b001111, "sdiv">; // sdiv r, r, i - def UDIVCCr : F3_1<2, 0b011110, "udivcc">; // udivcc r, r, r - def UDIVCCi : F3_2<2, 0b011110, "udivcc">; // udivcc r, r, i - def SDIVCCr : F3_1<2, 0b011111, "sdivcc">; // sdivcc r, r, r - def SDIVCCi : F3_2<2, 0b011111, "sdivcc">; // sdivcc r, r, i -} -*/ - -// Section A.11: DONE and RETRY - p181 -// Not used in the SparcV9 backend -/* -let isPrivileged = 1 in { - def DONE : F3_18<0, "done">; // done - def RETRY : F3_18<1, "retry">; // retry -} -*/ - -// Section A.12: Floating-Point Add and Subtract - p156 -def FADDS : F3_16<2, 0b110100, 0x41, "fadds">; // fadds frs1, frs2, frd -def FADDD : F3_16<2, 0b110100, 0x42, "faddd">; // faddd frs1, frs2, frd -def FADDQ : F3_16<2, 0b110100, 0x43, "faddq">; // faddq frs1, frs2, frd -def FSUBS : F3_16<2, 0b110100, 0x45, "fsubs">; // fsubs frs1, frs2, frd -def FSUBD : F3_16<2, 0b110100, 0x46, "fsubd">; // fsubd frs1, frs2, frd -def FSUBQ : F3_16<2, 0b110100, 0x47, "fsubq">; // fsubq frs1, frs2, frd - -// Section A.13: Floating-point compare - p159 -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 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 -def FCMPEQ : F3_15<2, 0b110101, 0b001010111, "fcmpeq">; // fcmpeq %fcc, r1, r2 -*/ - -// Section A.14: Convert floating-point to integer - p161 -def FSTOX : F3_14<2, 0b110100, 0b010000001, "fstox">; // fstox rs2, rd -def FDTOX : F3_14<2, 0b110100, 0b010000010, "fstox">; // fstox rs2, rd -def FQTOX : F3_14<2, 0b110100, 0b010000011, "fstox">; // fstox rs2, rd -def FSTOI : F3_14<2, 0b110100, 0b011010001, "fstoi">; // fstoi rs2, rd -def FDTOI : F3_14<2, 0b110100, 0b011010010, "fdtoi">; // fdtoi rs2, rd -def FQTOI : F3_14<2, 0b110100, 0b011010011, "fqtoi">; // fqtoi rs2, rd - -// Section A.15: Convert between floating-point formats - p162 -def FSTOD : F3_14<2, 0b110100, 0b011001001, "fstod">; // fstod rs2, rd -def FSTOQ : F3_14<2, 0b110100, 0b011001101, "fstoq">; // fstoq rs2, rd -def FDTOS : F3_14<2, 0b110100, 0b011000110, "fstos">; // fstos rs2, rd -def FDTOQ : F3_14<2, 0b110100, 0b011001110, "fdtoq">; // fdtoq rs2, rd -def FQTOS : F3_14<2, 0b110100, 0b011000111, "fqtos">; // fqtos rs2, rd -def FQTOD : F3_14<2, 0b110100, 0b011001011, "fqtod">; // fqtod rs2, rd - -// Section A.16: Convert integer to floating-point - p163 -def FXTOS : F3_14<2, 0b110100, 0b010000100, "fxtos">; // fxtos rs2, rd -def FXTOD : F3_14<2, 0b110100, 0b010001000, "fxtod">; // fxtod rs2, rd -def FXTOQ : F3_14<2, 0b110100, 0b010001100, "fxtoq">; // fxtoq rs2, rd -def FITOS : F3_14<2, 0b110100, 0b011000100, "fitos">; // fitos rs2, rd -def FITOD : F3_14<2, 0b110100, 0b011001000, "fitod">; // fitod rs2, rd -def FITOQ : F3_14<2, 0b110100, 0b011001100, "fitoq">; // fitoq rs2, rd - -// Section A.17: Floating-Point Move - p164 -def FMOVS : F3_14<2, 0b110100, 0b000000001, "fmovs">; // fmovs r, r -def FMOVD : F3_14<2, 0b110100, 0b000000010, "fmovs">; // fmovd r, r -//def FMOVQ : F3_14<2, 0b110100, 0b000000011, "fmovs">; // fmovq r, r -def FNEGS : F3_14<2, 0b110100, 0b000000101, "fnegs">; // fnegs r, r -def FNEGD : F3_14<2, 0b110100, 0b000000110, "fnegs">; // fnegs r, r -//def FNEGQ : F3_14<2, 0b110100, 0b000000111, "fnegs">; // fnegs r, r -def FABSS : F3_14<2, 0b110100, 0b000001001, "fabss">; // fabss r, r -def FABSD : F3_14<2, 0b110100, 0b000001010, "fabss">; // fabss r, r -//def FABSQ : F3_14<2, 0b110100, 0b000001011, "fabss">; // fabss r, r - -// Section A.18: Floating-Point Multiply and Divide - p165 -def FMULS : F3_16<2, 0b110100, 0b001001001, "fmuls">; // fmuls r, r, r -def FMULD : F3_16<2, 0b110100, 0b001001010, "fmuld">; // fmuld r, r, r -def FMULQ : F3_16<2, 0b110100, 0b001001011, "fmulq">; // fmulq r, r, r -def FSMULD : F3_16<2, 0b110100, 0b001101001, "fsmuld">; // fsmuls r, r, r -def FDMULQ : F3_16<2, 0b110100, 0b001101110, "fdmulq">; // fdmuls r, r, r -def FDIVS : F3_16<2, 0b110100, 0b001001101, "fdivs">; // fdivs r, r, r -def FDIVD : F3_16<2, 0b110100, 0b001001110, "fdivs">; // fdivd r, r, r -def FDIVQ : F3_16<2, 0b110100, 0b001001111, "fdivs">; // fdivq r, r, r - -// Section A.19: Floating-Point Square Root - p166 -def FSQRTS : F3_14<2, 0b110100, 0b000101001, "fsqrts">; // fsqrts r, r -def FSQRTD : F3_14<2, 0b110100, 0b000101010, "fsqrts">; // fsqrts r, r -def FSQRTQ : F3_14<2, 0b110100, 0b000101011, "fsqrts">; // fsqrts r, r - -// A.20: Flush Instruction Memory - p167 -// Not currently used - -// A.21: Flush Register Windows - p169 -// Not currently used - -// A.22: Illegal instruction Trap - p170 -// Not currently used - -// A.23: Implementation-Dependent Instructions - p171 -// Not currently used - -// Section A.24: Jump and Link - p172 -// 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 -def JMPLRETi : F3_2<2, 0b111000, "jmpl">; // jmpl [rs1+imm], rd - -// Section A.25: Load Floating-Point - p173 -def LDFr : F3_1<3, 0b100000, "ld">; // ld [rs1+rs2], rd -def LDFi : F3_2<3, 0b100000, "ld">; // ld [rs1+imm], rd -def LDDFr : F3_1<3, 0b100011, "ldd">; // ldd [rs1+rs2], rd -def LDDFi : F3_2<3, 0b100011, "ldd">; // ldd [rs1+imm], rd -def LDQFr : F3_1<3, 0b100010, "ldq">; // ldq [rs1+rs2], rd -def LDQFi : F3_2<3, 0b100010, "ldq">; // ldq [rs1+imm], rd -let isDeprecated = 1 in { - let rd = 0 in { - def LDFSRr : F3_1<3, 0b100001, "ld">; // ld [rs1+rs2], rd - def LDFSRi : F3_2<3, 0b100001, "ld">; // ld [rs1+imm], rd - } -} -let rd = 1 in { - def LDXFSRr : F3_1<3, 0b100001, "ldx">; // ldx [rs1+rs2], rd - def LDXFSRi : F3_2<3, 0b100001, "ldx">; // ldx [rs1+imm], rd -} - -// Section A.27: Load Integer - p178 -def LDSBr : F3_1<3, 0b001001, "ldsb">; // ldsb [rs1+rs2], rd -def LDSBi : F3_2<3, 0b001001, "ldsb">; // ldsb [rs1+imm], rd -def LDSHr : F3_1<3, 0b001010, "ldsh">; // ldsh [rs1+rs2], rd -def LDSHi : F3_2<3, 0b001010, "ldsh">; // ldsh [rs1+imm], rd -def LDSWr : F3_1<3, 0b001000, "ldsw">; // ldsh [rs1+rs2], rd -def LDSWi : F3_2<3, 0b001000, "ldsw">; // ldsh [rs1+imm], rd -def LDUBr : F3_1<3, 0b000001, "ldub">; // ldub [rs1+rs2], rd -def LDUBi : F3_2<3, 0b000001, "ldub">; // ldub [rs1+imm], rd -def LDUHr : F3_1<3, 0b000010, "lduh">; // lduh [rs1+rs2], rd -def LDUHi : F3_2<3, 0b000010, "lduh">; // lduh [rs1+imm], rd -// synonym: LD -def LDUWr : F3_1<3, 0b000000, "lduw">; // lduw [rs1+rs2], rd -def LDUWi : F3_2<3, 0b000000, "lduw">; // lduw [rs1+imm], rd -def LDXr : F3_1<3, 0b001011, "ldx">; // ldx [rs1+rs2], rd -def LDXi : F3_2<3, 0b001011, "ldx">; // ldx [rs1+imm], rd -/* -let isDeprecated = 1 in { - def LDDr : F3_1<3, 0b000011, "ldd">; // ldd [rs1+rs2], rd - def LDDi : F3_2<3, 0b000011, "ldd">; // ldd [rs1+imm], rd -} -*/ - -// Section A.31: Logical operations -def ANDr : F3_1<2, 0b000001, "and">; // and rs1, rs2, rd -def ANDi : F3_2<2, 0b000001, "and">; // and rs1, imm, rd -def ANDccr : F3_1<2, 0b010001, "andcc">; // andcc rs1, rs2, rd -def ANDcci : F3_2<2, 0b010001, "andcc">; // andcc rs1, imm, rd -def ANDNr : F3_1<2, 0b000101, "andn">; // andn rs1, rs2, rd -def ANDNi : F3_2<2, 0b000101, "andn">; // andn rs1, imm, rd -def ANDNccr : F3_1<2, 0b010101, "andncc">; // andncc rs1, rs2, rd -def ANDNcci : F3_2<2, 0b010101, "andncc">; // andncc rs1, imm, rd - -def ORr : F3_1<2, 0b000010, "or">; // or rs1, rs2, rd -def ORi : F3_2<2, 0b000010, "or">; // or rs1, imm, rd -def ORccr : F3_1<2, 0b010010, "orcc">; // orcc rs1, rs2, rd -def ORcci : F3_2<2, 0b010010, "orcc">; // orcc rs1, imm, rd -def ORNr : F3_1<2, 0b000110, "orn">; // orn rs1, rs2, rd -def ORNi : F3_2<2, 0b000110, "orn">; // orn rs1, imm, rd -def ORNccr : F3_1<2, 0b010110, "orncc">; // orncc rs1, rs2, rd -def ORNcci : F3_2<2, 0b010110, "orncc">; // orncc rs1, imm, rd - -def XORr : F3_1<2, 0b000011, "xor">; // xor rs1, rs2, rd -def XORi : F3_2<2, 0b000011, "xor">; // xor rs1, imm, rd -def XORccr : F3_1<2, 0b010011, "xorcc">; // xorcc rs1, rs2, rd -def XORcci : F3_2<2, 0b010011, "xorcc">; // xorcc rs1, imm, rd -def XNORr : F3_1<2, 0b000111, "xnor">; // xnor rs1, rs2, rd -def XNORi : F3_2<2, 0b000111, "xnor">; // xnor rs1, imm, rd -def XNORccr : F3_1<2, 0b010111, "xnorcc">; // xnorcc rs1, rs2, rd -def XNORcci : F3_2<2, 0b010111, "xnorcc">; // xnorcc rs1, imm, rd - -// Section A.32: Memory Barrier - p186 -// Not currently used in the SparcV9 backend - -// Section A.33: Move Floating-Point Register on Condition (FMOVcc) -// ======================= Single Floating Point ====================== -// For integer condition codes -def FMOVSA : F4_7<2, 0b110101, 0b1000, 0b000001, "fmovsa">; // fmovsa cc, r, r -def FMOVSN : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovsn">; // fmovsn cc, r, r -def FMOVSNE : F4_7<2, 0b110101, 0b1001, 0b000001, "fmovsne">; // fmovsne cc, r, r -def FMOVSE : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovse">; // fmovse cc, r, r -def FMOVSG : F4_7<2, 0b110101, 0b1010, 0b000001, "fmovsg">; // fmovsg cc, r, r -def FMOVSLE : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovsle">; // fmovsle cc, r, r -def FMOVSGE : F4_7<2, 0b110101, 0b1011, 0b000001, "fmovsge">; // fmovsge cc, r, r -def FMOVSL : F4_7<2, 0b110101, 0b0011, 0b000001, "fmovsl">; // fmovsl cc, r, r -def FMOVSGU : F4_7<2, 0b110101, 0b1100, 0b000001, "fmovsgu">; // fmovsgu cc, r, r -def FMOVSLEU : F4_7<2, 0b110101, 0b0100, 0b000001, "fmovsleu">; // fmovsleu cc, r, r -def FMOVSCC : F4_7<2, 0b110101, 0b1101, 0b000001, "fmovscc">; // fmovscc cc, r, r -def FMOVSCS : F4_7<2, 0b110101, 0b0101, 0b000001, "fmovscs">; // fmovscs cc, r, r -def FMOVSPOS : F4_7<2, 0b110101, 0b1110, 0b000001, "fmovspos">; // fmovspos cc, r, r -def FMOVSNEG : F4_7<2, 0b110101, 0b0110, 0b000001, "fmovsneg">; // fmovsneg cc, r, r -def FMOVSVC : F4_7<2, 0b110101, 0b1111, 0b000001, "fmovsvc">; // fmovsvc cc, r, r -def FMOVSVS : F4_7<2, 0b110101, 0b0111, 0b000001, "fmovsvs">; // fmovsvs cc, r, r - -// For floating-point condition codes -def FMOVSFA : F4_7<2, 0b110101, 0b0100, 0b000001, "fmovsfa">; // fmovsfa cc,r,r -def FMOVSFN : F4_7<2, 0b110101, 0b0000, 0b000001, "fmovsfn">; // fmovsfa cc,r,r -def FMOVSFU : F4_7<2, 0b110101, 0b0111, 0b000001, "fmovsfu">; // fmovsfu cc,r,r -def FMOVSFG : F4_7<2, 0b110101, 0b0110, 0b000001, "fmovsfg">; // fmovsfg cc,r,r -def FMOVSFUG : F4_7<2, 0b110101, 0b0101, 0b000001, "fmovsfug">; // fmovsfug cc,r,r -def FMOVSFL : F4_7<2, 0b110101, 0b0100, 0b000001, "fmovsfl">; // fmovsfl cc,r,r -def FMOVSFUL : F4_7<2, 0b110101, 0b0011, 0b000001, "fmovsful">; // fmovsful cc,r,r -def FMOVSFLG : F4_7<2, 0b110101, 0b0010, 0b000001, "fmovsflg">; // fmovsflg cc,r,r -def FMOVSFNE : F4_7<2, 0b110101, 0b0001, 0b000001, "fmovsfne">; // fmovsfne cc,r,r -def FMOVSFE : F4_7<2, 0b110101, 0b1001, 0b000001, "fmovsfe">; // fmovsfe cc,r,r -def FMOVSFUE : F4_7<2, 0b110101, 0b1010, 0b000001, "fmovsfue">; // fmovsfue cc,r,r -def FMOVSFGE : F4_7<2, 0b110101, 0b1011, 0b000001, "fmovsge">; // fmovsge cc,r,r -def FMOVSFUGE : F4_7<2, 0b110101, 0b1100, 0b000001, "fmovsfuge">;// fmovsfuge cc,r,r -def FMOVSFLE : F4_7<2, 0b110101, 0b1101, 0b000001, "fmovsfle">; // fmovsfle cc,r,r -def FMOVSFULE : F4_7<2, 0b110101, 0b1110, 0b000001, "fmovsfule">;// fmovsfule cc,r,r -def FMOVSFO : F4_7<2, 0b110101, 0b1111, 0b000001, "fmovsfo">; // fmovsfo cc,r,r - -// ======================= Double Floating Point ====================== -// For integer condition codes -def FMOVDA : F4_7<2, 0b110101, 0b1000, 0b000010, "fmovda">; // fmovda cc, r, r -def FMOVDN : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovdn">; // fmovdn cc, r, r -def FMOVDNE : F4_7<2, 0b110101, 0b1001, 0b000010, "fmovdne">; // fmovdne cc, r, r -def FMOVDE : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovde">; // fmovde cc, r, r -def FMOVDG : F4_7<2, 0b110101, 0b1010, 0b000010, "fmovdg">; // fmovdg cc, r, r -def FMOVDLE : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovdle">; // fmovdle cc, r, r -def FMOVDGE : F4_7<2, 0b110101, 0b1011, 0b000010, "fmovdge">; // fmovdge cc, r, r -def FMOVDL : F4_7<2, 0b110101, 0b0011, 0b000010, "fmovdl">; // fmovdl cc, r, r -def FMOVDGU : F4_7<2, 0b110101, 0b1100, 0b000010, "fmovdgu">; // fmovdgu cc, r, r -def FMOVDLEU : F4_7<2, 0b110101, 0b0100, 0b000010, "fmovdleu">; // fmovdleu cc, r, r -def FMOVDCC : F4_7<2, 0b110101, 0b1101, 0b000010, "fmovdcc">; // fmovdcc cc, r, r -def FMOVDCS : F4_7<2, 0b110101, 0b0101, 0b000010, "fmovdcs">; // fmovdcs cc, r, r -def FMOVDPOS : F4_7<2, 0b110101, 0b1110, 0b000010, "fmovdpos">; // fmovdpos cc, r, r -def FMOVDNEG : F4_7<2, 0b110101, 0b0110, 0b000010, "fmovdneg">; // fmovdneg cc, r, r -def FMOVDVC : F4_7<2, 0b110101, 0b1111, 0b000010, "fmovdvc">; // fmovdvc cc, r, r -def FMOVDVS : F4_7<2, 0b110101, 0b0111, 0b000010, "fmovdvs">; // fmovdvs cc, r, r - -// For floating-point condition codes -def FMOVDFA : F4_7<2, 0b110101, 0b0100, 0b000010, "fmovdfa">; // fmovdfa cc,r,r -def FMOVDFN : F4_7<2, 0b110101, 0b0000, 0b000010, "fmovdfn">; // fmovdfa cc,r,r -def FMOVDFU : F4_7<2, 0b110101, 0b0111, 0b000010, "fmovdfu">; // fmovdfu cc,r,r -def FMOVDFG : F4_7<2, 0b110101, 0b0110, 0b000010, "fmovdfg">; // fmovdfg cc,r,r -def FMOVDFUG : F4_7<2, 0b110101, 0b0101, 0b000010, "fmovdfug">; // fmovdfug cc,r,r -def FMOVDFL : F4_7<2, 0b110101, 0b0100, 0b000010, "fmovdfl">; // fmovdfl cc,r,r -def FMOVDFUL : F4_7<2, 0b110101, 0b0011, 0b000010, "fmovdful">; // fmovdful cc,r,r -def FMOVDFLG : F4_7<2, 0b110101, 0b0010, 0b000010, "fmovdflg">; // fmovdflg cc,r,r -def FMOVDFNE : F4_7<2, 0b110101, 0b0001, 0b000010, "fmovdfne">; // fmovdfne cc,r,r -def FMOVDFE : F4_7<2, 0b110101, 0b1001, 0b000010, "fmovdfe">; // fmovdfe cc,r,r -def FMOVDFUE : F4_7<2, 0b110101, 0b1010, 0b000010, "fmovdfue">; // fmovdfue cc,r,r -def FMOVDFGE : F4_7<2, 0b110101, 0b1011, 0b000010, "fmovdge">; // fmovdge cc,r,r -def FMOVDFUGE : F4_7<2, 0b110101, 0b1100, 0b000010, "fmovdfuge">;// fmovdfuge cc,r,r -def FMOVDFLE : F4_7<2, 0b110101, 0b1101, 0b000010, "fmovdfle">; // fmovdfle cc,r,r -def FMOVDFULE : F4_7<2, 0b110101, 0b1110, 0b000010, "fmovdfule">;// fmovdfule cc,r,r -def FMOVDFO : F4_7<2, 0b110101, 0b1111, 0b000010, "fmovdfo">; // fmovdfo cc,r,r - -// ======================= Quad Floating Point ====================== -// For integer condition codes -def FMOVQA : F4_7<2, 0b110101, 0b1000, 0b000011, "fmovqa">; // fmovqa cc, r, r -def FMOVQN : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqn">; // fmovqn cc, r, r -def FMOVQNE : F4_7<2, 0b110101, 0b1001, 0b000011, "fmovqne">; // fmovqne cc, r, r -def FMOVQE : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqe">; // fmovqe cc, r, r -def FMOVQG : F4_7<2, 0b110101, 0b1010, 0b000011, "fmovqg">; // fmovqg cc, r, r -def FMOVQLE : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqle">; // fmovqle cc, r, r -def FMOVQGE : F4_7<2, 0b110101, 0b1011, 0b000011, "fmovqge">; // fmovqge cc, r, r -def FMOVQL : F4_7<2, 0b110101, 0b0011, 0b000011, "fmovql">; // fmovql cc, r, r -def FMOVQGU : F4_7<2, 0b110101, 0b1100, 0b000011, "fmovqgu">; // fmovqgu cc, r, r -def FMOVQLEU : F4_7<2, 0b110101, 0b0100, 0b000011, "fmovqleu">; // fmovqleu cc, r, r -def FMOVQCC : F4_7<2, 0b110101, 0b1101, 0b000011, "fmovqcc">; // fmovqcc cc, r, r -def FMOVQCS : F4_7<2, 0b110101, 0b0101, 0b000011, "fmovqcs">; // fmovqcs cc, r, r -def FMOVQPOS : F4_7<2, 0b110101, 0b1110, 0b000011, "fmovqpos">; // fmovqpos cc, r, r -def FMOVQNEG : F4_7<2, 0b110101, 0b0110, 0b000011, "fmovqneg">; // fmovqneg cc, r, r -def FMOVQVC : F4_7<2, 0b110101, 0b1111, 0b000011, "fmovqvc">; // fmovqvc cc, r, r -def FMOVQVS : F4_7<2, 0b110101, 0b0111, 0b000011, "fmovqvs">; // fmovqvs cc, r, r - -// For floating-point condition codes -def FMOVQFA : F4_7<2, 0b110101, 0b0100, 0b000011, "fmovqfa">; // fmovqfa cc,r,r -def FMOVQFN : F4_7<2, 0b110101, 0b0000, 0b000011, "fmovqfn">; // fmovqfa cc,r,r -def FMOVQFU : F4_7<2, 0b110101, 0b0111, 0b000011, "fmovqfu">; // fmovqfu cc,r,r -def FMOVQFG : F4_7<2, 0b110101, 0b0110, 0b000011, "fmovqfg">; // fmovqfg cc,r,r -def FMOVQFUG : F4_7<2, 0b110101, 0b0101, 0b000011, "fmovqfug">; // fmovqfug cc,r,r -def FMOVQFL : F4_7<2, 0b110101, 0b0100, 0b000011, "fmovqfl">; // fmovqfl cc,r,r -def FMOVQFUL : F4_7<2, 0b110101, 0b0011, 0b000011, "fmovqful">; // fmovqful cc,r,r -def FMOVQFLG : F4_7<2, 0b110101, 0b0010, 0b000011, "fmovqflg">; // fmovqflg cc,r,r -def FMOVQFNE : F4_7<2, 0b110101, 0b0001, 0b000011, "fmovqfne">; // fmovqfne cc,r,r -def FMOVQFE : F4_7<2, 0b110101, 0b1001, 0b000011, "fmovqfe">; // fmovqfe cc,r,r -def FMOVQFUE : F4_7<2, 0b110101, 0b1010, 0b000011, "fmovqfue">; // fmovqfue cc,r,r -def FMOVQFGE : F4_7<2, 0b110101, 0b1011, 0b000011, "fmovqge">; // fmovqge cc,r,r -def FMOVQFUGE : F4_7<2, 0b110101, 0b1100, 0b000011, "fmovqfuge">;// fmovqfuge cc,r,r -def FMOVQFLE : F4_7<2, 0b110101, 0b1101, 0b000011, "fmovqfle">; // fmovqfle cc,r,r -def FMOVQFULE : F4_7<2, 0b110101, 0b1110, 0b000011, "fmovqfule">;// fmovqfule cc,r,r -def FMOVQFO : F4_7<2, 0b110101, 0b1111, 0b000011, "fmovqfo">; // fmovqfo cc,r,r - -// Section A.34: Move FP Register on Integer Register condition (FMOVr) - p192 -def FMOVRSZ : F4_6<2, 0b110101, 0b001, 0b00101, "fmovrsz">; //fmovsrz r,r,rd -def FMOVRSLEZ : F4_6<2, 0b110101, 0b010, 0b00101, "fmovrslez">;//fmovsrz r,r,rd -def FMOVRSLZ : F4_6<2, 0b110101, 0b011, 0b00101, "fmovrslz">; //fmovsrz r,r,rd -def FMOVRSNZ : F4_6<2, 0b110101, 0b101, 0b00101, "fmovrsne">; //fmovsrz r,r,rd -def FMOVRSGZ : F4_6<2, 0b110101, 0b110, 0b00101, "fmovrsgz">; //fmovsrz r,r,rd -def FMOVRSGEZ : F4_6<2, 0b110101, 0b111, 0b00101, "fmovrsgez">;//fmovsrz r,r,rd - -def FMOVRDZ : F4_6<2, 0b110101, 0b001, 0b00110, "fmovrdz">; //fmovsrz r,r,rd -def FMOVRDLEZ : F4_6<2, 0b110101, 0b010, 0b00110, "fmovrdlez">;//fmovsrz r,r,rd -def FMOVRDLZ : F4_6<2, 0b110101, 0b011, 0b00110, "fmovrdlz">; //fmovsrz r,r,rd -def FMOVRDNZ : F4_6<2, 0b110101, 0b101, 0b00110, "fmovrdne">; //fmovsrz r,r,rd -def FMOVRDGZ : F4_6<2, 0b110101, 0b110, 0b00110, "fmovrdgz">; //fmovsrz r,r,rd -def FMOVRDGEZ : F4_6<2, 0b110101, 0b111, 0b00110, "fmovrdgez">;//fmovsrz r,r,rd - -def FMOVRQZ : F4_6<2, 0b110101, 0b001, 0b00111, "fmovrqz">; //fmovsrz r,r,rd -def FMOVRQLEZ : F4_6<2, 0b110101, 0b010, 0b00111, "fmovrqlez">;//fmovsrz r,r,rd -def FMOVRQLZ : F4_6<2, 0b110101, 0b011, 0b00111, "fmovrqlz">; //fmovsrz r,r,rd -def FMOVRQNZ : F4_6<2, 0b110101, 0b101, 0b00111, "fmovrqne">; //fmovsrz r,r,rd -def FMOVRQGZ : F4_6<2, 0b110101, 0b110, 0b00111, "fmovrqgz">; //fmovsrz r,r,rd -def FMOVRQGEZ : F4_6<2, 0b110101, 0b111, 0b00111, "fmovrqgez">;//fmovsrz r,r,rd - - -// Section A.35: Move Integer Register on Condition (MOVcc) - p194 -// For integer condition codes -def MOVAr : F4_3<2, 0b101100, 0b1000, "mova">; // mova i/xcc, rs2, rd -def MOVAi : F4_4<2, 0b101100, 0b1000, "mova">; // mova i/xcc, imm, rd -def MOVNr : F4_3<2, 0b101100, 0b0000, "movn">; // movn i/xcc, rs2, rd -def MOVNi : F4_4<2, 0b101100, 0b0000, "movn">; // movn i/xcc, imm, rd -def MOVNEr : F4_3<2, 0b101100, 0b1001, "movne">; // movne i/xcc, rs2, rd -def MOVNEi : F4_4<2, 0b101100, 0b1001, "movne">; // movne i/xcc, imm, rd -def MOVEr : F4_3<2, 0b101100, 0b0001, "move">; // move i/xcc, rs2, rd -def MOVEi : F4_4<2, 0b101100, 0b0001, "move">; // move i/xcc, imm, rd -def MOVGr : F4_3<2, 0b101100, 0b1010, "movg">; // movg i/xcc, rs2, rd -def MOVGi : F4_4<2, 0b101100, 0b1010, "movg">; // movg i/xcc, imm, rd -def MOVLEr : F4_3<2, 0b101100, 0b0010, "movle">; // movle i/xcc, rs2, rd -def MOVLEi : F4_4<2, 0b101100, 0b0010, "movle">; // movle i/xcc, imm, rd -def MOVGEr : F4_3<2, 0b101100, 0b1011, "movge">; // movge i/xcc, rs2, rd -def MOVGEi : F4_4<2, 0b101100, 0b1011, "movge">; // movge i/xcc, imm, rd -def MOVLr : F4_3<2, 0b101100, 0b0011, "movl">; // movl i/xcc, rs2, rd -def MOVLi : F4_4<2, 0b101100, 0b0011, "movl">; // movl i/xcc, imm, rd -def MOVGUr : F4_3<2, 0b101100, 0b1100, "movgu">; // movgu i/xcc, rs2, rd -def MOVGUi : F4_4<2, 0b101100, 0b1100, "movgu">; // movgu i/xcc, imm, rd -def MOVLEUr : F4_3<2, 0b101100, 0b0100, "movleu">; // movleu i/xcc, rs2, rd -def MOVLEUi : F4_4<2, 0b101100, 0b0100, "movleu">; // movleu i/xcc, imm, rd -def MOVCCr : F4_3<2, 0b101100, 0b1101, "movcc">; // movcc i/xcc, rs2, rd -def MOVCCi : F4_4<2, 0b101100, 0b1101, "movcc">; // movcc i/xcc, imm, rd -def MOVCSr : F4_3<2, 0b101100, 0b0101, "movcs">; // movcs i/xcc, rs2, rd -def MOVCSi : F4_4<2, 0b101100, 0b0101, "movcs">; // movcs i/xcc, imm, rd -def MOVPOSr : F4_3<2, 0b101100, 0b1110, "movpos">; // movpos i/xcc, rs2, rd -def MOVPOSi : F4_4<2, 0b101100, 0b1110, "movpos">; // movpos i/xcc, imm, rd -def MOVNEGr : F4_3<2, 0b101100, 0b0110, "movneg">; // movneg i/xcc, rs2, rd -def MOVNEGi : F4_4<2, 0b101100, 0b0110, "movneg">; // movneg i/xcc, imm, rd -def MOVVCr : F4_3<2, 0b101100, 0b1111, "movvc">; // movvc i/xcc, rs2, rd -def MOVVCi : F4_4<2, 0b101100, 0b1111, "movvc">; // movvc i/xcc, imm, rd -def MOVVSr : F4_3<2, 0b101100, 0b0111, "movvs">; // movvs i/xcc, rs2, rd -def MOVVSi : F4_4<2, 0b101100, 0b0111, "movvs">; // movvs i/xcc, imm, rd - -// For floating-point condition codes -def MOVFAr : F4_3<2, 0b101100, 0b1000, "movfa">; // movfa i/xcc, rs2, rd -def MOVFAi : F4_4<2, 0b101100, 0b1000, "movfa">; // movfa i/xcc, imm, rd -def MOVFNr : F4_3<2, 0b101100, 0b0000, "movfn">; // movfn i/xcc, rs2, rd -def MOVFNi : F4_4<2, 0b101100, 0b0000, "movfn">; // movfn i/xcc, imm, rd -def MOVFUr : F4_3<2, 0b101100, 0b0111, "movfu">; // movfu i/xcc, rs2, rd -def MOVFUi : F4_4<2, 0b101100, 0b0111, "movfu">; // movfu i/xcc, imm, rd -def MOVFGr : F4_3<2, 0b101100, 0b0110, "movfg">; // movfg i/xcc, rs2, rd -def MOVFGi : F4_4<2, 0b101100, 0b0110, "movfg">; // movfg i/xcc, imm, rd -def MOVFUGr : F4_3<2, 0b101100, 0b0101, "movfug">; // movfug i/xcc, rs2, rd -def MOVFUGi : F4_4<2, 0b101100, 0b0101, "movfug">; // movfug i/xcc, imm, rd -def MOVFLr : F4_3<2, 0b101100, 0b0100, "movfl">; // movfl i/xcc, rs2, rd -def MOVFLi : F4_4<2, 0b101100, 0b0100, "movfl">; // movfl i/xcc, imm, rd -def MOVFULr : F4_3<2, 0b101100, 0b0011, "movful">; // movful i/xcc, rs2, rd -def MOVFULi : F4_4<2, 0b101100, 0b0011, "movful">; // movful i/xcc, imm, rd -def MOVFLGr : F4_3<2, 0b101100, 0b0010, "movflg">; // movflg i/xcc, rs2, rd -def MOVFLGi : F4_4<2, 0b101100, 0b0010, "movflg">; // movflg i/xcc, imm, rd -def MOVFNEr : F4_3<2, 0b101100, 0b0001, "movfne">; // movfne i/xcc, rs2, rd -def MOVFNEi : F4_4<2, 0b101100, 0b0001, "movfne">; // movfne i/xcc, imm, rd -def MOVFEr : F4_3<2, 0b101100, 0b1001, "movfe">; // movfe i/xcc, rs2, rd -def MOVFEi : F4_4<2, 0b101100, 0b1001, "movfe">; // movfe i/xcc, imm, rd -def MOVFUEr : F4_3<2, 0b101100, 0b1010, "movfue">; // movfue i/xcc, rs2, rd -def MOVFUEi : F4_4<2, 0b101100, 0b1010, "movfue">; // movfue i/xcc, imm, rd -def MOVFGEr : F4_3<2, 0b101100, 0b1011, "movfge">; // movfge i/xcc, rs2, rd -def MOVFGEi : F4_4<2, 0b101100, 0b1011, "movfge">; // movfge i/xcc, imm, rd -def MOVFUGEr : F4_3<2, 0b101100, 0b1100, "movfuge">; // movfuge i/xcc, rs2, rd -def MOVFUGEi : F4_4<2, 0b101100, 0b1100, "movfuge">; // movfuge i/xcc, imm, rd -def MOVFLEr : F4_3<2, 0b101100, 0b1101, "movfle">; // movfle i/xcc, rs2, rd -def MOVFLEi : F4_4<2, 0b101100, 0b1101, "movfle">; // movfle i/xcc, imm, rd -def MOVFULEr : F4_3<2, 0b101100, 0b1110, "movfule">; // movfule i/xcc, rs2, rd -def MOVFULEi : F4_4<2, 0b101100, 0b1110, "movfule">; // movfule i/xcc, imm, rd -def MOVFOr : F4_3<2, 0b101100, 0b1111, "movfo">; // movfo i/xcc, rs2, rd -def MOVFOi : F4_4<2, 0b101100, 0b1111, "movfo">; // movfo i/xcc, imm, rd - -// Section A.36: Move Integer Register on Register Condition (MOVR) - p198 -def MOVRZr : F3_5<2, 0b101111, 0b001, "movrz">; // movrz rs1, rs2, rd -def MOVRZi : F3_6<2, 0b101111, 0b001, "movrz">; // movrz rs1, imm, rd -def MOVRLEZr : F3_5<2, 0b101111, 0b010, "movrlez">; // movrlez rs1, rs2, rd -def MOVRLEZi : F3_6<2, 0b101111, 0b010, "movrlez">; // movrlez rs1, imm, rd -def MOVRLZr : F3_5<2, 0b101111, 0b011, "movrlz">; // movrlz rs1, rs2, rd -def MOVRLZi : F3_6<2, 0b101111, 0b011, "movrlz">; // movrlz rs1, imm, rd -def MOVRNZr : F3_5<2, 0b101111, 0b101, "movrnz">; // movrnz rs1, rs2, rd -def MOVRNZi : F3_6<2, 0b101111, 0b101, "movrnz">; // movrnz rs1, imm, rd -def MOVRGZr : F3_5<2, 0b101111, 0b110, "movrgz">; // movrgz rs1, rs2, rd -def MOVRGZi : F3_6<2, 0b101111, 0b110, "movrgz">; // movrgz rs1, imm, rd -def MOVRGEZr : F3_5<2, 0b101111, 0b111, "movrgez">; // movrgez rs1, rs2, rd -def MOVRGEZi : F3_6<2, 0b101111, 0b111, "movrgez">; // movrgez rs1, imm, rd - -// Section A.37: Multiply and Divide (64-bit) - p199 -def MULXr : F3_1<2, 0b001001, "mulx">; // mulx r, r, r -def MULXi : F3_2<2, 0b001001, "mulx">; // mulx r, i, r -def SDIVXr : F3_1<2, 0b101101, "sdivx">; // sdivx r, r, r -def SDIVXi : F3_2<2, 0b101101, "sdivx">; // sdivx r, i, r -def UDIVXr : F3_1<2, 0b001101, "udivx">; // udivx r, r, r -def UDIVXi : F3_2<2, 0b001101, "udivx">; // udivx r, i, r - -// Section A.38: Multiply (32-bit) - p200 -// Not used in the SparcV9 backend -/* -let Inst{13} = 0 in { - def UMULr : F3_1<2, 0b001010, "umul">; // umul r, r, r - def SMULr : F3_1<2, 0b001011, "smul">; // smul r, r, r - def UMULCCr : F3_1<2, 0b011010, "umulcc">; // mulcc r, r, r - def SMULCCr : F3_1<2, 0b011011, "smulcc">; // smulcc r, r, r -} -let Inst{13} = 1 in { - def UMULi : F3_1<2, 0b001010, "umul">; // umul r, i, r - def SMULi : F3_1<2, 0b001011, "smul">; // smul r, i, r - def UMULCCi : F3_1<2, 0b011010, "umulcc">; // umulcc r, i, r - def SMULCCi : F3_1<2, 0b011011, "smulcc">; // smulcc r, i, r -} -*/ - -// Section A.39: Multiply Step - p202 -// Not currently used in the SparcV9 backend +// Register File Description +//===----------------------------------------------------------------------===// -// Section A.40: No operation - p204 -// NOP is really a pseudo-instruction (special case of SETHI) -let op2 = 0b100 in { - let rd = 0 in { - let imm = 0 in { - def NOP : F2_1<"nop">; // nop - } - } -} +include "SparcV9RegisterInfo.td" -// Section A.41: Population Count - p205 -// Not currently used in the SparcV9 backend +//===----------------------------------------------------------------------===// +// Instruction Descriptions +//===----------------------------------------------------------------------===// -// Section A.42: Prefetch Data - p206 -// Not currently used in the SparcV9 backend +include "SparcV9InstrInfo.td" -// Section A.43: Read Privileged Register - p211 -// Not currently used in the SparcV9 backend +def SparcV9InstrInfo : InstrInfo { + let PHIInst = PHI; -// Section A.44: Read State Register -// The only instr from this section currently used is RDCCR -let rs1 = 2 in { - def RDCCR : F3_17<2, 0b101000, "rd">; // rd %ccr, r + // Define how we want to layout our TargetSpecific information field. + let TSFlagsFields = []; + let TSFlagsShifts = []; } -// Section A.46: SAVE and RESTORE - p217 -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 A.47: SAVED and RESTORED - p219 -// Not currently used in SparcV9 backend - -// Section A.48: SETHI - p220 -let op2 = 0b100 in { - def SETHI : F2_1<"sethi">; // sethi -} +//===----------------------------------------------------------------------===// +// Declare the target which we are implementing +//===----------------------------------------------------------------------===// -// Section A.49: Shift - p221 -// Not currently used in the SparcV9 backend -/* - uses 5 least significant bits of rs2 -let x = 0 in { - def SLLr5 : F3_11<2, 0b100101, "sll">; // sll r, r, r - def SRLr5 : F3_11<2, 0b100110, "srl">; // srl r, r, r - def SRAr5 : F3_11<2, 0b100111, "sra">; // sra r, r, r - def SLLXr5 : F3_11<2, 0b100101, "sllx">; // sllx r, r, r - def SRLXr5 : F3_11<2, 0b100110, "srlx">; // srlx r, r, r - def SRAXr5 : F3_11<2, 0b100111, "srax">; // srax r, r, r -} -*/ +def SparcV9 : Target { + // FIXME: Specify the callee saved registers. + let CalleeSavedRegisters = []; -// uses 6 least significant bits of rs2 -let x = 0 in { - def SLLr5 : F3_11<2, 0b100101, "sll">; // sll r, r, r - def SRLr5 : F3_11<2, 0b100110, "srl">; // srl r, r, r - def SRAr5 : F3_11<2, 0b100111, "sra">; // sra r, r, r -} -let x = 1 in { - def SLLXr6 : F3_11<2, 0b100101, "sllx">; // sllx r, r, r - def SRLXr6 : F3_11<2, 0b100110, "srlx">; // srlx r, r, r - def SRAXr6 : F3_11<2, 0b100111, "srax">; // srax r, r, r -} + // Pointers are 64-bits in size. + let PointerType = i64; -def SLLi5 : F3_12<2, 0b100101, "sll">; // sll r, shcnt32, r -def SRLi5 : F3_12<2, 0b100110, "srl">; // srl r, shcnt32, r -def SRAi5 : F3_12<2, 0b100111, "sra">; // sra r, shcnt32, r -def SLLXi6 : F3_13<2, 0b100101, "sllx">; // sllx r, shcnt64, r -def SRLXi6 : F3_13<2, 0b100110, "srlx">; // srlx r, shcnt64, r -def SRAXi6 : F3_13<2, 0b100111, "srax">; // srax r, shcnt64, r - -// Section A.50: Sofware-Initiated Reset - p223 -// Not currently used in the SparcV9 backend - -// Section A.51: Store Barrier - p224 -// Not currently used in the SparcV9 backend - -// Section A.52: Store Floating-point - p225 -// Store instructions all want their rd register first -def STFr : F3_1rd<3, 0b100100, "st">; // st r, [r+r] -def STFi : F3_2rd<3, 0b100100, "st">; // st r, [r+i] -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 SparcV9 backend -/* -def STQFr : F3_1rd<3, 0b100110, "stq">; // stq r, [r+r] -def STQFi : F3_2rd<3, 0b100110, "stq">; // stq r, [r+i] -*/ - -// WARNING: We encode %fsr as 1, because we only use STXFSRx, but STFSRx wants -// you to encode %fsr as 0. If STFSRx instrs are ever enabled, this will -// need to be worked around. -/* -let isDeprecated = 1 in { - def STFSRr : F3_1rd<3, 0b100101, "st">; // st %fsr, [r+r] - def STFSRi : F3_2rd<3, 0b100101, "st">; // st %fsr, [r+i] -} -*/ -def STXFSRr : F3_1rd<3, 0b100101, "stx">; // stx %fsr, [r+r] -def STXFSRi : F3_2rd<3, 0b100101, "stx">; // stx %fsr, [r+i] - -// Section A.53: Store Floating-Point into Alternate Space - p227 -// Not currently used in the SparcV9 backend - -// Section A.54: Store Integer - p229 -// Store instructions all want their rd register first -def STBr : F3_1rd<3, 0b000101, "stb">; // stb r, [r+r] -def STBi : F3_2rd<3, 0b000101, "stb">; // stb r, [r+i] -def STHr : F3_1rd<3, 0b000110, "sth">; // sth r, [r+r] -def STHi : F3_2rd<3, 0b000110, "sth">; // sth r, [r+i] -def STWr : F3_1rd<3, 0b000100, "stw">; // stw r, [r+r] -def STWi : F3_2rd<3, 0b000100, "stw">; // stw r, [r+i] -def STXr : F3_1rd<3, 0b001110, "stx">; // stx r, [r+r] -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 SparcV9 backend - -// Section A.56: Subtract - p233 -def SUBr : F3_1<2, 0b000100, "sub">; // sub r, r, r -def SUBi : F3_2<2, 0b000100, "sub">; // sub r, i, r -def SUBccr : F3_1<2, 0b010100, "subcc">; // subcc r, r, r -def SUBcci : F3_2<2, 0b010100, "subcc">; // subcc r, i, r -def SUBCr : F3_1<2, 0b001100, "subc">; // subc r, r, r -def SUBCi : F3_2<2, 0b001100, "subc">; // subc r, i, r -def SUBCccr : F3_1<2, 0b011100, "subccc">; // subccc r, r, r -def SUBCcci : F3_2<2, 0b011100, "subccc">; // subccc r, i, r - -// FIXME: More...? - -// Section A.63: Write State Register - p244 -let rd = 2 in { - def WRCCRr : F3_1<2, 0b110000, "wr">; // wr r, r, %y/ccr/etc - def WRCCRi : F3_2<2, 0b110000, "wr">; // wr r, i, %y/ccr/etc + // Information about the instructions... + let InstructionSet = SparcV9InstrInfo; } From brukman at cs.uiuc.edu Tue Aug 10 13:31:12 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 13:31:12 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/CodeEmitterGen.cpp Message-ID: <200408101831.NAA17466@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: CodeEmitterGen.cpp updated: 1.34 -> 1.35 --- Log message: Use the target name instead of hard-coding SparcV9. --- Diffs of the changes: (+3 -3) Index: llvm/utils/TableGen/CodeEmitterGen.cpp diff -u llvm/utils/TableGen/CodeEmitterGen.cpp:1.34 llvm/utils/TableGen/CodeEmitterGen.cpp:1.35 --- llvm/utils/TableGen/CodeEmitterGen.cpp:1.34 Tue Aug 10 10:05:18 2004 +++ llvm/utils/TableGen/CodeEmitterGen.cpp Tue Aug 10 13:31:01 2004 @@ -20,15 +20,15 @@ using namespace llvm; void CodeEmitterGen::run(std::ostream &o) { + CodeGenTarget Target; std::vector Insts = Records.getAllDerivedDefinitions("Instruction"); EmitSourceFileHeader("Machine Code Emitter", o); - std::string Namespace = "V9::"; - std::string ClassName = "SparcV9CodeEmitter::"; + std::string Namespace = Insts[0]->getValueAsString("Namespace") + "::"; //const std::string &Namespace = Inst->getValue("Namespace")->getName(); - o << "unsigned " << ClassName + o << "unsigned " << Target.getName() << "CodeEmitter::" << "getBinaryCodeForInstr(MachineInstr &MI) {\n" << " unsigned Value = 0;\n" << " DEBUG(std::cerr << MI);\n" From criswell at cs.uiuc.edu Tue Aug 10 13:32:17 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue, 10 Aug 2004 13:32:17 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/lib/Target/CBackend/Writer.cpp Message-ID: <200408101832.NAA17565@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/CBackend: Writer.cpp updated: 1.192 -> 1.192.2.1 --- Log message: Merged in mainline. --- Diffs of the changes: (+7 -3) Index: llvm/lib/Target/CBackend/Writer.cpp diff -u llvm/lib/Target/CBackend/Writer.cpp:1.192 llvm/lib/Target/CBackend/Writer.cpp:1.192.2.1 --- llvm/lib/Target/CBackend/Writer.cpp:1.192 Sun Jul 25 17:36:35 2004 +++ llvm/lib/Target/CBackend/Writer.cpp Tue Aug 10 13:32:06 2004 @@ -1390,9 +1390,13 @@ Out << ")"; return; case Intrinsic::vaend: - Out << "va_end(*(va_list*)&"; - writeOperand(I.getOperand(1)); - Out << ")"; + if (!isa(I.getOperand(1))) { + Out << "va_end(*(va_list*)&"; + writeOperand(I.getOperand(1)); + Out << ")"; + } else { + Out << "va_end(*(va_list*)0)"; + } return; case Intrinsic::vacopy: Out << "0;"; From criswell at cs.uiuc.edu Tue Aug 10 13:33:49 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue, 10 Aug 2004 13:33:49 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/test/Regression/CodeGen/CBackend/2004-08-09-va-end-null.ll Message-ID: <200408101833.NAA17671@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/CodeGen/CBackend: 2004-08-09-va-end-null.ll added (r1.1.2.1) --- Log message: Merged from mainline on August 10, 2004. --- Diffs of the changes: (+7 -0) Index: llvm/test/Regression/CodeGen/CBackend/2004-08-09-va-end-null.ll diff -c /dev/null llvm/test/Regression/CodeGen/CBackend/2004-08-09-va-end-null.ll:1.1.2.1 *** /dev/null Tue Aug 10 13:33:49 2004 --- llvm/test/Regression/CodeGen/CBackend/2004-08-09-va-end-null.ll Tue Aug 10 13:33:39 2004 *************** *** 0 **** --- 1,7 ---- + declare void %llvm.va_end(sbyte*) + + void %test() { + call void %llvm.va_end( sbyte* null ) + ret void + } + From llvm at cs.uiuc.edu Tue Aug 10 13:59:46 2004 From: llvm at cs.uiuc.edu (LLVM) Date: Tue, 10 Aug 2004 13:59:46 -0500 Subject: [llvm-commits] CVS: llvm/projects/HowToUseJIT/ Message-ID: <200408101859.NAA18044@zion.cs.uiuc.edu> Changes in directory llvm/projects/HowToUseJIT: --- Log message: Directory /var/cvs/llvm/llvm/projects/HowToUseJIT added to the repository --- Diffs of the changes: (+0 -0) From brukman at cs.uiuc.edu Tue Aug 10 14:03:42 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 14:03:42 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Message-ID: <200408101903.OAA18143@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCInstrFormats.td updated: 1.7 -> 1.8 --- Log message: DForm 5/6 extended mneumonics take 3 arguments. --- Diffs of the changes: (+10 -0) Index: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.7 llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.8 --- llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.7 Tue Aug 10 13:07:55 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Tue Aug 10 14:03:31 2004 @@ -185,6 +185,11 @@ class DForm_5_ext opcode, bit ppc64, bit vmx> : DForm_5 { let L = 0; + let ArgCount = 3; + let Arg0Type = Imm3.Value; + let Arg1Type = Gpr.Value; + let Arg2Type = Simm16.Value; + let Arg3Type = 0; } class DForm_6 opcode, bit ppc64, bit vmx> @@ -195,6 +200,11 @@ class DForm_6_ext opcode, bit ppc64, bit vmx> : DForm_6 { let L = 0; + let ArgCount = 3; + let Arg0Type = Imm3.Value; + let Arg1Type = Gpr.Value; + let Arg2Type = Simm16.Value; + let Arg3Type = 0; } class DForm_7 opcode, bit ppc64, bit vmx> From lattner at cs.uiuc.edu Tue Aug 10 14:06:48 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 14:06:48 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200408101906.OAA15595@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.89 -> 1.90 --- Log message: Convert Ii32 instructions over to use the asmprinter generator --- Diffs of the changes: (+16 -16) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.89 llvm/lib/Target/X86/X86InstrInfo.td:1.90 --- llvm/lib/Target/X86/X86InstrInfo.td:1.89 Tue Aug 10 11:22:02 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Tue Aug 10 14:06:36 2004 @@ -133,10 +133,10 @@ 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, dag ops, string asm> : Ii<"", o, f, Imm8 >, II; -class Ii16 o, Format f, dag ops, string asm> : Ii<"", o, f, Imm16>, II; -class Ii32 o, Format f> : Ii; +class Ii o, Format f, ImmType i> : X86Inst<"", o, f, NoMem, i>; +class Ii8 o, Format f, dag ops, string asm> : Ii, II; +class Ii16 o, Format f, dag ops, string asm> : Ii, II; +class Ii32 o, Format f, dag ops, string asm> : Ii, II; class Im8i8 o, Format f> : X86Inst; class Im16i16 o, Format f> : X86Inst; @@ -292,7 +292,7 @@ def MOV32rr : I<0x89, MRMDestReg>, II<(ops R32:$dst, R32 :$src), "mov $dst, $src">; def MOV8ri : Ii8 <0xB0, AddRegFrm, (ops R8 :$dst, i8imm :$src), "mov $dst, $src">; def MOV16ri : Ii16<0xB8, AddRegFrm, (ops R16:$dst, i16imm:$src), "mov $dst, $src">, OpSize; -def MOV32ri : Ii32<"", 0xB8, AddRegFrm >, II<(ops R32:$dst, i32imm:$src), "mov $dst, $src">; +def MOV32ri : Ii32<0xB8, AddRegFrm, (ops R32:$dst, i32imm:$src), "mov $dst, $src">; 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 @@ -495,7 +495,7 @@ def AND8ri : Ii8 <0x80, MRM4r, (ops R8:$dst, R8:$src1, i8imm:$src2), "and $dst, $src2">; def AND16ri : Ii16 <0x81, MRM4r, (ops R16:$dst, R16:$src1, i16imm:$src2), "and $dst, $src2">, OpSize; -def AND32ri : Ii32 <"and", 0x81, MRM4r >; +def AND32ri : Ii32 <0x81, MRM4r, (ops R32:$dst, R32:$src1, i32imm:$src2), "and $dst, $src2">; 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 @@ -521,7 +521,7 @@ def OR8ri : Ii8 <0x80, MRM1r, (ops R8:$dst, R8:$src1, i8imm:$src2), "or $dst, $src2">; def OR16ri : Ii16 <0x81, MRM1r, (ops R16:$dst, R16:$src1, i16imm:$src2), "or $dst, $src2">, OpSize; -def OR32ri : Ii32 <"or" , 0x81, MRM1r >; +def OR32ri : Ii32 <0x81, MRM1r, (ops R32:$dst, R32:$src1, i32imm:$src2), "or $dst, $src2">; 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 @@ -547,7 +547,7 @@ def XOR8ri : Ii8 <0x80, MRM6r, (ops R8:$dst, R8:$src1, i8imm:$src2), "xor $dst, $src2">; def XOR16ri : Ii16 <0x81, MRM6r, (ops R16:$dst, R16:$src1, i16imm:$src2), "xor $dst, $src2">, OpSize; -def XOR32ri : Ii32 <"xor", 0x81, MRM6r >; +def XOR32ri : Ii32 <0x81, MRM6r, (ops R32:$dst, R32:$src1, i32imm:$src2), "xor $dst, $src2">; 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 @@ -644,7 +644,7 @@ def ADD8ri : Ii8 <0x80, MRM0r, (ops R8:$dst, R8:$src1, i8imm:$src2), "add $dst, $src2">; def ADD16ri : Ii16 <0x81, MRM0r, (ops R16:$dst, R16:$src1, i16imm:$src2), "add $dst, $src2">, OpSize; -def ADD32ri : Ii32 <"add", 0x81, MRM0r >; +def ADD32ri : Ii32 <0x81, MRM0r, (ops R32:$dst, R32:$src1, i32imm:$src2), "add $dst, $src2">; 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 @@ -658,7 +658,7 @@ II<(ops R32:$dst, R32:$src1, R32:$src2), "adc $dst, $src2">; def ADC32mr : Im32 <"adc", 0x11, MRMDestMem>; // [mem32] += R32+Carry def ADC32rm : Im32 <"adc", 0x13, MRMSrcMem >; // R32 += [mem32]+Carry -def ADC32ri : Ii32 <"adc", 0x81, MRM2r >; // R32 += I32+Carry +def ADC32ri : Ii32 <0x81, MRM2r, (ops R32:$dst, R32:$src1, i32imm:$src2), "adc $dst, $src2">; // R32 += I32+Carry def ADC32ri8 : Ii8 <0x83, MRM2r, (ops R32:$dst, R32:$src1, i8imm:$src2), "adc $dst, $src2">; // R32 += I8+Carry def ADC32mi : Im32i32<"adc", 0x81, MRM2m >; // [mem32] += I32+Carry def ADC32mi8 : Im32i8 <"adc", 0x83, MRM2m >; // [mem32] += I8+Carry @@ -675,7 +675,7 @@ def SUB8ri : Ii8 <0x80, MRM5r, (ops R8:$dst, R8:$src1, i8imm:$src2), "sub $dst, $src2">; def SUB16ri : Ii16 <0x81, MRM5r, (ops R16:$dst, R16:$src1, i16imm:$src2), "sub $dst, $src2">, OpSize; -def SUB32ri : Ii32 <"sub", 0x81, MRM5r >; +def SUB32ri : Ii32 <0x81, MRM5r, (ops R32:$dst, R32:$src1, i32imm:$src2), "sub $dst, $src2">; 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 @@ -689,7 +689,7 @@ II<(ops R32:$dst, R32:$src1, R32:$src2), "adc $dst, $src2">; def SBB32mr : Im32 <"sbb", 0x19, MRMDestMem>; // [mem32] -= R32+Carry def SBB32rm : Im32 <"sbb", 0x1B, MRMSrcMem >; // R32 -= [mem32]+Carry -def SBB32ri : Ii32 <"sbb", 0x81, MRM3r >; // R32 -= I32+Carry +def SBB32ri : Ii32 <0x81, MRM3r, (ops R32:$dst, R32:$src1, i32imm:$src2), "sbb $dst, $src2">; // R32 -= I32+Carry def SBB32ri8 : Ii8 <0x83, MRM3r, (ops R32:$dst, R32:$src1, i8imm:$src2), "sbb $dst, $src2">; // R32 -= I8+Carry def SBB32mi : Im32i32<"sbb", 0x81, MRM3m >; // [mem32] -= I32+Carry def SBB32mi8 : Im32i8 <"sbb", 0x83, MRM3m >; // [mem32] -= I8+Carry @@ -705,7 +705,7 @@ // These are suprisingly enough not two address instructions! def IMUL16rri : Ii16 <0x69, MRMSrcReg, (ops R16:$dst, R16:$src1, i16imm:$src2), "imul $dst, $src1, $src2">, OpSize; // R16 = R16*I16 -def IMUL32rri : Ii32 <"imul", 0x69, MRMSrcReg>; // R32 = R32*I32 +def IMUL32rri : Ii32 <0x69, MRMSrcReg, (ops R32:$dst, R32:$src1, i32imm:$src2), "imul $dst, $src1, $src2">; // R32 = R32*I32 def IMUL16rri8 : Ii8 <0x6B, MRMSrcReg, (ops R16:$dst, R16:$src1, i8imm:$src2), "imul $dst, $src1, $src2">, OpSize; // R16 = R16*I8 def IMUL32rri8 : Ii8 <0x6B, MRMSrcReg, (ops R32:$dst, R32:$src1, i8imm:$src2), "imul $dst, $src1, $src2">; // R32 = R32*I8 def IMUL16rmi : Im16i16<"imul",0x69, MRMSrcMem>, OpSize; // R16 = [mem16]*I16 @@ -730,7 +730,7 @@ def TEST8ri : Ii8 <0xF6, MRM0r, (ops R8:$dst, i8imm:$src), "test $dst, $src">; // flags = R8 & imm8 def TEST16ri : Ii16 <0xF7, MRM0r, (ops R16:$dst, i16imm:$src), "test $dst, $src">, OpSize; // flags = R16 & imm16 -def TEST32ri : Ii32 <"test", 0xF7, MRM0r >; // flags = R32 & imm32 +def TEST32ri : Ii32 <0xF7, MRM0r, (ops R32:$dst, i32imm:$src), "test $dst, $src">; // 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 @@ -797,8 +797,8 @@ def CMP16rm : Im16 <"cmp", 0x3B, MRMSrcMem >, OpSize; // compare R16, [mem16] def CMP32rm : Im32 <"cmp", 0x3B, MRMSrcMem >; // compare R32, [mem32] def CMP8ri : Ii8 <0x80, MRM7r, (ops R16:$dst, i8imm:$src), "cmp $dst, $src">; // compare R8, imm8 -def CMP16ri : Ii16 <0x81, MRM7r, (ops R16:$dst, i16imm:$src), "cmp $dst, $src">, OpSize; // compare R16, imm16 -def CMP32ri : Ii32 <"cmp", 0x81, MRM7r >; // compare R32, imm32 +def CMP16ri : Ii16 <0x81, MRM7r, (ops R16:$dst, i16imm:$src), "cmp $dst, $src">, OpSize; // compare R16, imm16 +def CMP32ri : Ii32 <0x81, MRM7r, (ops R32:$dst, i32imm:$src), "cmp $dst, $src">; // 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 From reid at x10sys.com Tue Aug 10 14:14:46 2004 From: reid at x10sys.com (Reid Spencer) Date: Tue, 10 Aug 2004 14:14:46 -0500 Subject: [llvm-commits] CVS: llvm/projects/HowToUseJIT/HowToUseJIT.cpp Makefile Message-ID: <200408101914.OAA18275@zion.cs.uiuc.edu> Changes in directory llvm/projects/HowToUseJIT: HowToUseJIT.cpp added (r1.1) Makefile added (r1.1) --- Log message: Adding a simple example of how to use the JIT. Contributed by Valery A. Khamenya. THANKS, Valery! --- Diffs of the changes: (+168 -0) Index: llvm/projects/HowToUseJIT/HowToUseJIT.cpp diff -c /dev/null llvm/projects/HowToUseJIT/HowToUseJIT.cpp:1.1 *** /dev/null Tue Aug 10 14:14:46 2004 --- llvm/projects/HowToUseJIT/HowToUseJIT.cpp Tue Aug 10 14:14:36 2004 *************** *** 0 **** --- 1,153 ---- + //===--- HowToUseJIT.cpp - An example use of the JIT ----------------------===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by Valery A. Khamenya and is distributed under the + // University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This tool provides a single point of access to the LLVM compilation tools. + // It has many options. To discover the options supported please refer to the + // tools' manual page (docs/CommandGuide/html/llvmc.html) or run the tool with + // the --help option. + // + //===------------------------------------------------------------------------=== + + // Goal: + // The goal of this snippet is to create in the memory + // the LLVM module consisting of two functions as follow: + // + // int add1(int x) { + // return x+1; + // } + // + // int foo() { + // return add1(10); + // } + // + // then compile the module via JIT, then execute the `foo' + // function and return result to a driver, i.e. to a "host program". + // + // Some remarks and questions: + // + // - could we invoke some code using noname functions too? + // e.g. evaluate "foo()+foo()" without fears to introduce + // conflict of temporary function name with some real + // existing function name? + // + + #include + + #include + #include + #include + #include + #include + + #include "llvm/ExecutionEngine/ExecutionEngine.h" + #include "llvm/ExecutionEngine/GenericValue.h" + + + using namespace llvm; + + int main() { + + // Create some module to put our function into it. + Module *M = new Module("test"); + + + // We are about to create the add1 function: + Function *Add1F; + + { + // first create type for the single argument of add1 function: + // the type is 'int ()' + std::vector ArgT(1); + ArgT[0] = Type::IntTy; + + // now create full type of the add1 function: + FunctionType *Add1T = FunctionType::get(Type::IntTy, // type of result + ArgT, + /*not vararg*/false); + + // Now create the add1 function entry and + // insert this entry into module M + // (By passing a module as the last parameter to the Function constructor, + // it automatically gets appended to the Module.) + Add1F = new Function(Add1T, + Function::ExternalLinkage, // maybe too much + "add1", M); + + // Add a basic block to the function... (again, it automatically inserts + // because of the last argument.) + BasicBlock *BB = new BasicBlock("EntryBlock of add1 function", Add1F); + + // Get pointers to the constant `1'... + Value *One = ConstantSInt::get(Type::IntTy, 1); + + // Get pointers to the integer argument of the add1 function... + assert(Add1F->abegin() != Add1F->aend()); // Make sure there's an arg + Argument &ArgX = Add1F->afront(); // Get the arg + + // Create the add instruction... does not insert... + Instruction *Add = BinaryOperator::create(Instruction::Add, One, &ArgX, + "addresult"); + + // explicitly insert it into the basic block... + BB->getInstList().push_back(Add); + + // Create the return instruction and add it to the basic block + BB->getInstList().push_back(new ReturnInst(Add)); + + // function add1 is ready + } + + + // now we going to create function `foo': + Function *FooF; + + { + // Create the foo function type: + FunctionType *FooT = + FunctionType::get(Type::IntTy, // result has type: 'int ()' + std::vector(), // no arguments + /*not vararg*/false); + + // create the entry for function `foo' and insert + // this entry into module M: + FooF = + new Function(FooT, + Function::ExternalLinkage, // too wide? + "foo", M); + + // Add a basic block to the FooF function... + BasicBlock *BB = new BasicBlock("EntryBlock of add1 function", FooF); + + // Get pointers to the constant `10'... + Value *Ten = ConstantSInt::get(Type::IntTy, 10); + + // Put the argument Ten on stack and make call: + // ... + std::vector Params; + Params.push_back(Ten); + CallInst * Add1CallRes = new CallInst(Add1F, Params, "add1", BB); + + // Create the return instruction and add it to the basic block + BB->getInstList().push_back(new ReturnInst(Add1CallRes)); + + } + + // Now we going to create JIT ?? + ExistingModuleProvider* MP = new ExistingModuleProvider(M); + ExecutionEngine* EE = ExecutionEngine::create( MP, true ); + + // Call the `foo' function with no arguments: + std::vector noargs; + GenericValue gv = EE->runFunction(FooF, noargs); + + // import result of execution: + std::cout << "Result: " << gv.IntVal << std:: endl; + + return 0; + } Index: llvm/projects/HowToUseJIT/Makefile diff -c /dev/null llvm/projects/HowToUseJIT/Makefile:1.1 *** /dev/null Tue Aug 10 14:14:46 2004 --- llvm/projects/HowToUseJIT/Makefile Tue Aug 10 14:14:36 2004 *************** *** 0 **** --- 1,15 ---- + ##===- projects/HowToUseJIT/Makefile -----------------------*- Makefile -*-===## + # + # The LLVM Compiler Infrastructure + # + # This file was developed by Valery A. Khamenya and is distributed under + # the University of Illinois Open Source License. See LICENSE.TXT for details. + # + ##===----------------------------------------------------------------------===## + LEVEL = ../.. + TOOLNAME = HowToUseJIT + USEDLIBS = lli-jit lli-interpreter codegen executionengine x86 selectiondag \ + scalaropts analysis.a transformutils.a bcreader target.a vmcore \ + support.a + + include $(LEVEL)/Makefile.common From reid at x10sys.com Tue Aug 10 14:19:01 2004 From: reid at x10sys.com (Reid Spencer) Date: Tue, 10 Aug 2004 14:19:01 -0500 Subject: [llvm-commits] CVS: llvm/projects/HowToUseJIT/HowToUseJIT.cpp Message-ID: <200408101919.OAA18301@zion.cs.uiuc.edu> Changes in directory llvm/projects/HowToUseJIT: HowToUseJIT.cpp updated: 1.1 -> 1.2 --- Log message: Fix a copy & paste error .. correct the description of the program. --- Diffs of the changes: (+2 -4) Index: llvm/projects/HowToUseJIT/HowToUseJIT.cpp diff -u llvm/projects/HowToUseJIT/HowToUseJIT.cpp:1.1 llvm/projects/HowToUseJIT/HowToUseJIT.cpp:1.2 --- llvm/projects/HowToUseJIT/HowToUseJIT.cpp:1.1 Tue Aug 10 14:14:36 2004 +++ llvm/projects/HowToUseJIT/HowToUseJIT.cpp Tue Aug 10 14:18:51 2004 @@ -7,10 +7,8 @@ // //===----------------------------------------------------------------------===// // -// This tool provides a single point of access to the LLVM compilation tools. -// It has many options. To discover the options supported please refer to the -// tools' manual page (docs/CommandGuide/html/llvmc.html) or run the tool with -// the --help option. +// This small program provides an example of how to quickly build a small +// module with two functions and execute it with the JIT. // //===------------------------------------------------------------------------=== From lattner at cs.uiuc.edu Tue Aug 10 15:17:53 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 15:17:53 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200408102017.PAA18629@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.90 -> 1.91 --- Log message: This purely mechanical patch gives the "I" tblgen class operand list and asm string operands, and adjusts all users to pass them in instead of using II. --- Diffs of the changes: (+244 -317) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.90 llvm/lib/Target/X86/X86InstrInfo.td:1.91 --- llvm/lib/Target/X86/X86InstrInfo.td:1.90 Tue Aug 10 14:06:36 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Tue Aug 10 15:17:41 2004 @@ -126,7 +126,7 @@ //===----------------------------------------------------------------------===// // Instruction templates... -class I o, Format f> : X86Inst<"", o, f, NoMem, NoImm>; +class I o, Format f, dag ops, string asm> : X86Inst<"", o, f, NoMem, NoImm>, II; class Im o, Format f, MemType m> : X86Inst; class Im8 o, Format f> : Im; @@ -149,16 +149,16 @@ // Instruction list... // -def PHI : I<0, Pseudo>; // PHI node. -def NOOP : I<0x90, RawFrm>, II<(ops), "nop">; // nop +def PHI : I<0, Pseudo, (ops), "PHINODE">; // PHI node. +def NOOP : I<0x90, RawFrm, (ops), "nop">; // nop -def ADJCALLSTACKDOWN : I<0, Pseudo>; -def ADJCALLSTACKUP : I<0, Pseudo>; -def IMPLICIT_USE : I<0, Pseudo>; -def IMPLICIT_DEF : I<0, Pseudo>; +def ADJCALLSTACKDOWN : I<0, Pseudo, (ops), "#ADJCALLSTACKDOWN">; +def ADJCALLSTACKUP : I<0, Pseudo, (ops), "#ADJCALLSTACKUP">; +def IMPLICIT_USE : I<0, Pseudo, (ops), "#IMPLICIT_USE">; +def IMPLICIT_DEF : I<0, Pseudo, (ops), "#IMPLICIT_DEF">; let isTerminator = 1 in let Defs = [FP0, FP1, FP2, FP3, FP4, FP5, FP6] in - def FP_REG_KILL : I<0, Pseudo>; + def FP_REG_KILL : I<0, Pseudo, (ops), "#FP_REG_KILL">; //===----------------------------------------------------------------------===// // Control Flow Instructions... @@ -166,26 +166,26 @@ // Return instruction... let isTerminator = 1, isReturn = 1, isBarrier = 1 in - def RET : I<0xC3, RawFrm>, II<(ops), "ret">; + def RET : I<0xC3, RawFrm, (ops), "ret">; // All branches are RawFrm, Void, Branch, and Terminators let isBranch = 1, isTerminator = 1 in - class IBr opcode> : I; + class IBr opcode, dag ops, string asm> : I; let isBarrier = 1 in - def JMP : IBr<0xE9>, II<(ops i32imm:$dst), "jmp $dst">; -def JB : IBr<0x82>, TB, II<(ops i32imm:$dst), "jb $dst">; -def JAE : IBr<0x83>, TB, II<(ops i32imm:$dst), "jae $dst">; -def JE : IBr<0x84>, TB, II<(ops i32imm:$dst), "je $dst">; -def JNE : IBr<0x85>, TB, II<(ops i32imm:$dst), "jne $dst">; -def JBE : IBr<0x86>, TB, II<(ops i32imm:$dst), "jbe $dst">; -def JA : IBr<0x87>, TB, II<(ops i32imm:$dst), "ja $dst">; -def JS : IBr<0x88>, TB, II<(ops i32imm:$dst), "js $dst">; -def JNS : IBr<0x89>, TB, II<(ops i32imm:$dst), "jns $dst">; -def JL : IBr<0x8C>, TB, II<(ops i32imm:$dst), "jl $dst">; -def JGE : IBr<0x8D>, TB, II<(ops i32imm:$dst), "jge $dst">; -def JLE : IBr<0x8E>, TB, II<(ops i32imm:$dst), "jle $dst">; -def JG : IBr<0x8F>, TB, II<(ops i32imm:$dst), "jg $dst">; + def JMP : IBr<0xE9, (ops i32imm:$dst), "jmp $dst">; +def JB : IBr<0x82, (ops i32imm:$dst), "jb $dst">, TB; +def JAE : IBr<0x83, (ops i32imm:$dst), "jae $dst">, TB; +def JE : IBr<0x84, (ops i32imm:$dst), "je $dst">, TB; +def JNE : IBr<0x85, (ops i32imm:$dst), "jne $dst">, TB; +def JBE : IBr<0x86, (ops i32imm:$dst), "jbe $dst">, TB; +def JA : IBr<0x87, (ops i32imm:$dst), "ja $dst">, TB; +def JS : IBr<0x88, (ops i32imm:$dst), "js $dst">, TB; +def JNS : IBr<0x89, (ops i32imm:$dst), "jns $dst">, TB; +def JL : IBr<0x8C, (ops i32imm:$dst), "jl $dst">, TB; +def JGE : IBr<0x8D, (ops i32imm:$dst), "jge $dst">, TB; +def JLE : IBr<0x8E, (ops i32imm:$dst), "jle $dst">, TB; +def JG : IBr<0x8F, (ops i32imm:$dst), "jg $dst">, TB; //===----------------------------------------------------------------------===// @@ -195,7 +195,7 @@ // 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, NoMem, NoImm>; // FIXME: 'call' doesn't allow 'OFFSET' - def CALL32r : I<0xFF, MRM2r>, II<(ops R32:$dst), "call $dst">; + def CALL32r : I<0xFF, MRM2r, (ops R32:$dst), "call $dst">; def CALL32m : Im32<"call", 0xFF, MRM2m>; } @@ -203,21 +203,21 @@ //===----------------------------------------------------------------------===// // Miscellaneous Instructions... // -def LEAVE : I<0xC9, RawFrm>, Imp<[EBP,ESP],[EBP,ESP]>, - II<(ops), "leave">; -def POP32r : I<0x58, AddRegFrm>, Imp<[ESP],[ESP]>, - II<(ops R32:$reg), "pop $reg">; +def LEAVE : I<0xC9, RawFrm, + (ops), "leave">, Imp<[EBP,ESP],[EBP,ESP]>; +def POP32r : I<0x58, AddRegFrm, + (ops R32:$reg), "pop $reg">, Imp<[ESP],[ESP]>; let isTwoAddress = 1 in // R32 = bswap R32 - def BSWAP32r : I<0xC8, AddRegFrm>, TB, - II<(ops R32:$dst, R32:$src), "bswap $dst">; + def BSWAP32r : I<0xC8, AddRegFrm, + (ops R32:$dst, R32:$src), "bswap $dst">, TB; -def XCHG8rr : I<0x86, MRMDestReg>, // xchg R8, R8 - II<(ops R8:$src1, R8:$src2), "xchg $src1, $src2">; -def XCHG16rr : I<0x87, MRMDestReg>, OpSize, // xchg R16, R16 - II<(ops R16:$src1, R16:$src2), "xchg $src1, $src2">; -def XCHG32rr : I<0x87, MRMDestReg>, // xchg R32, R32 - II<(ops R32:$src1, R32:$src2), "xchg $src1, $src2">; +def XCHG8rr : I<0x86, MRMDestReg, // xchg R8, R8 + (ops R8:$src1, R8:$src2), "xchg $src1, $src2">; +def XCHG16rr : I<0x87, MRMDestReg, // xchg R16, R16 + (ops R16:$src1, R16:$src2), "xchg $src1, $src2">, OpSize; +def XCHG32rr : I<0x87, MRMDestReg, // xchg R32, R32 + (ops R32:$src1, R32:$src2), "xchg $src1, $src2">; def XCHG8mr : Im8 <"xchg", 0x86, MRMDestMem>; // xchg [mem8], R8 def XCHG16mr : Im16<"xchg", 0x87, MRMDestMem>, OpSize; // xchg [mem16], R16 @@ -230,52 +230,44 @@ def LEA32r : Im32<"lea", 0x8D, MRMSrcMem>; // R32 = lea [mem] -def REP_MOVSB : I<0xA4, RawFrm>, REP, - Imp<[ECX,EDI,ESI], [ECX,EDI,ESI]>, - II<(ops), "rep movsb">; -def REP_MOVSW : I<0xA5, RawFrm>, REP, OpSize, - Imp<[ECX,EDI,ESI], [ECX,EDI,ESI]>, - II<(ops), "rep movsw">; -def REP_MOVSD : I<0xA5, RawFrm>, REP, - Imp<[ECX,EDI,ESI], [ECX,EDI,ESI]>, - II<(ops), "rep movsd">; - -def REP_STOSB : I<0xAA, RawFrm>, REP, - Imp<[AL,ECX,EDI], [ECX,EDI]>, - II<(ops), "rep stosb">; -def REP_STOSW : I<0xAB, RawFrm>, REP, OpSize, - Imp<[AX,ECX,EDI], [ECX,EDI]>, - II<(ops), "rep stosw">; -def REP_STOSD : I<0xAB, RawFrm>, REP, - Imp<[EAX,ECX,EDI], [ECX,EDI]>, - II<(ops), "rep stosd">; +def REP_MOVSB : I<0xA4, RawFrm, (ops), "rep movsb">, + Imp<[ECX,EDI,ESI], [ECX,EDI,ESI]>, REP; +def REP_MOVSW : I<0xA5, RawFrm, (ops), "rep movsw">, + Imp<[ECX,EDI,ESI], [ECX,EDI,ESI]>, REP, OpSize; +def REP_MOVSD : I<0xA5, RawFrm, (ops), "rep movsd">, + Imp<[ECX,EDI,ESI], [ECX,EDI,ESI]>, REP; + +def REP_STOSB : I<0xAA, RawFrm, (ops), "rep stosb">, + Imp<[AL,ECX,EDI], [ECX,EDI]>, REP; +def REP_STOSW : I<0xAB, RawFrm, (ops), "rep stosw">, + Imp<[AX,ECX,EDI], [ECX,EDI]>, REP, OpSize; +def REP_STOSD : I<0xAB, RawFrm, (ops), "rep stosd">, + Imp<[EAX,ECX,EDI], [ECX,EDI]>, REP; + //===----------------------------------------------------------------------===// // Input/Output Instructions... // -def IN8rr : I<0xEC, RawFrm>, Imp<[DX], [AL]>, // AL = in I/O address DX - II<(ops), "in %AL, %DX">; -def IN16rr : I<0xED, RawFrm>, Imp<[DX], [AX]>, OpSize, // AX = in I/O address DX - II<(ops), "in %AX, %DX">; -def IN32rr : I<0xED, RawFrm>, Imp<[DX],[EAX]>, // EAX = in I/O address DX - II<(ops), "in %EAX, %DX">; - -def IN8ri : Ii16<0xE4, RawFrm, (ops i16imm:$port), // AL = in [I/O address] - "in %AL, $port">, - Imp<[], [AL]>; -def IN16ri : Ii16<0xE5, RawFrm, (ops i16imm:$port), // AX = in [I/O address] - "in %AX, $port">, - Imp<[], [AX]>, OpSize; -def IN32ri : Ii16<0xE5, RawFrm, (ops i16imm:$port), // EAX = in [I/O address] - "in %EAX, $port">, - Imp<[],[EAX]>; - -def OUT8rr : I<0xEE, RawFrm>, Imp<[DX, AL], []>, - II<(ops), "out %DX, %AL">; -def OUT16rr : I<0xEF, RawFrm>, Imp<[DX, AX], []>, OpSize, - II<(ops), "out %DX, %AX">; -def OUT32rr : I<0xEF, RawFrm>, Imp<[DX, EAX], []>, - II<(ops), "out %DX, %EAX">; +def IN8rr : I<0xEC, RawFrm, (ops), + "in %AL, %DX">, Imp<[DX], [AL]>; +def IN16rr : I<0xED, RawFrm, (ops), + "in %AX, %DX">, Imp<[DX], [AX]>, OpSize; +def IN32rr : I<0xED, RawFrm, (ops), + "in %EAX, %DX">, Imp<[DX],[EAX]>; + +def IN8ri : Ii16<0xE4, RawFrm, (ops i16imm:$port), + "in %AL, $port">, Imp<[], [AL]>; +def IN16ri : Ii16<0xE5, RawFrm, (ops i16imm:$port), + "in %AX, $port">, Imp<[], [AX]>, OpSize; +def IN32ri : Ii16<0xE5, RawFrm, (ops i16imm:$port), + "in %EAX, $port">, Imp<[],[EAX]>; + +def OUT8rr : I<0xEE, RawFrm, (ops), + "out %DX, %AL">, Imp<[DX, AL], []>; +def OUT16rr : I<0xEF, RawFrm, (ops), + "out %DX, %AX">, Imp<[DX, AX], []>, OpSize; +def OUT32rr : I<0xEF, RawFrm, (ops), + "out %DX, %EAX">, Imp<[DX, EAX], []>; def OUT8ir : Ii16<0xE6, RawFrm, (ops i16imm:$port), "out $port, %AL">, Imp<[AL], []>; @@ -287,9 +279,9 @@ //===----------------------------------------------------------------------===// // Move Instructions... // -def MOV8rr : I<0x88, MRMDestReg>, II<(ops R8 :$dst, R8 :$src), "mov $dst, $src">; -def MOV16rr : I<0x89, MRMDestReg>, OpSize, II<(ops R16:$dst, R16 :$src), "mov $dst, $src">; -def MOV32rr : I<0x89, MRMDestReg>, II<(ops R32:$dst, R32 :$src), "mov $dst, $src">; +def MOV8rr : I<0x88, MRMDestReg, (ops R8 :$dst, R8 :$src), "mov $dst, $src">; +def MOV16rr : I<0x89, MRMDestReg, (ops R16:$dst, R16:$src), "mov $dst, $src">, OpSize; +def MOV32rr : I<0x89, MRMDestReg, (ops R32:$dst, R32:$src), "mov $dst, $src">; def MOV8ri : Ii8 <0xB0, AddRegFrm, (ops R8 :$dst, i8imm :$src), "mov $dst, $src">; def MOV16ri : Ii16<0xB8, AddRegFrm, (ops R16:$dst, i16imm:$src), "mov $dst, $src">, OpSize; def MOV32ri : Ii32<0xB8, AddRegFrm, (ops R32:$dst, i32imm:$src), "mov $dst, $src">; @@ -310,42 +302,42 @@ // // Extra precision multiplication -def MUL8r : I<0xF6, MRM4r>, Imp<[AL],[AX]>, // AL,AH = AL*R8 - II<(ops R8:$src), "mul $src">; -def MUL16r : I<0xF7, MRM4r>, Imp<[AX],[AX,DX]>, OpSize, // AX,DX = AX*R16 - II<(ops R16:$src), "mul $src">; -def MUL32r : I<0xF7, MRM4r>, Imp<[EAX],[EAX,EDX]>, // EAX,EDX = EAX*R32 - II<(ops R32:$src), "mul $src">; +def MUL8r : I<0xF6, MRM4r, (ops R8:$src), "mul $src">, + Imp<[AL],[AX]>; // AL,AH = AL*R8 +def MUL16r : I<0xF7, MRM4r, (ops R16:$src), "mul $src">, + Imp<[AX],[AX,DX]>, OpSize; // AX,DX = AX*R16 +def MUL32r : I<0xF7, MRM4r, (ops R32:$src), "mul $src">, + 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 DIV8r : I<0xF6, MRM6r>, Imp<[AX],[AX]>, // AX/r8 = AL,AH - II<(ops R8:$src), "div $src">; -def DIV16r : I<0xF7, MRM6r>, Imp<[AX,DX],[AX,DX]>, OpSize, // DX:AX/r16 = AX,DX - II<(ops R16:$src), "div $src">; -def DIV32r : I<0xF7, MRM6r>, Imp<[EAX,EDX],[EAX,EDX]>, // EDX:EAX/r32 = EAX,EDX - II<(ops R32:$src), "div $src">; +def DIV8r : I<0xF6, MRM6r, (ops R8:$src), "div $src">, + Imp<[AX],[AX]>; // AX/r8 = AL,AH +def DIV16r : I<0xF7, MRM6r, (ops R16:$src), "div $src">, + Imp<[AX,DX],[AX,DX]>, OpSize; // DX:AX/r16 = AX,DX +def DIV32r : I<0xF7, MRM6r, (ops R32:$src), "div $src">, + 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 IDIV8r : I<0xF6, MRM7r>, Imp<[AX],[AX]>, // AX/r8 = AL,AH - II<(ops R8:$src), "idiv $src">; -def IDIV16r: I<0xF7, MRM7r>, Imp<[AX,DX],[AX,DX]>, OpSize, // DX:AX/r16 = AX,DX - II<(ops R16:$src), "idiv $src">; -def IDIV32r: I<0xF7, MRM7r>, Imp<[EAX,EDX],[EAX,EDX]>, // EDX:EAX/r32 = EAX,EDX - II<(ops R32:$src), "idiv $src">; +def IDIV8r : I<0xF6, MRM7r, (ops R8:$src), "idiv $src">, + Imp<[AX],[AX]>; // AX/r8 = AL,AH +def IDIV16r: I<0xF7, MRM7r, (ops R16:$src), "idiv $src">, + Imp<[AX,DX],[AX,DX]>, OpSize; // DX:AX/r16 = AX,DX +def IDIV32r: I<0xF7, MRM7r, (ops R32:$src), "idiv $src">, + 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 : I<0x98, RawFrm>, Imp<[AL],[AH]>, II<(ops), "cbw">; // AX = signext(AL) -def CWD : I<0x99, RawFrm>, Imp<[AX],[DX]>, II<(ops), "cwd">; // DX:AX = signext(AX) -def CDQ : I<0x99, RawFrm>, Imp<[EAX],[EDX]>, II<(ops), "cdq">; // EDX:EAX = signext(EAX) +def CBW : I<0x98, RawFrm, (ops), "cbw">, Imp<[AL],[AH]>; // AX = signext(AL) +def CWD : I<0x99, RawFrm, (ops), "cwd">, Imp<[AX],[DX]>; // DX:AX = signext(AX) +def CDQ : I<0x99, RawFrm, (ops), "cdq">, Imp<[EAX],[EDX]>; // EDX:EAX = signext(EAX) //===----------------------------------------------------------------------===// @@ -354,138 +346,123 @@ let isTwoAddress = 1 in { // Conditional moves -def CMOVB16rr : I<0x42, MRMSrcReg>, TB, OpSize, // if ; +def CMOVB16rr : I<0x42, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), + "cmovb $dst, $src2">, TB, OpSize; // if , TB, OpSize; // if , TB, // if ; +def CMOVB32rr : I<0x42, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), + "cmovb $dst, $src2">, TB; // if , TB; // if , TB, OpSize, // if >=u, R16 = R16 - II<(ops R16:$dst, R16:$src1, R16:$src2), "cmovae $dst, $src2">; +def CMOVAE16rr: I<0x43, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), + "cmovae $dst, $src2">, TB, OpSize; // if >=u, R16 = R16 def CMOVAE16rm: Im16<"cmovae", 0x43, MRMSrcMem>, TB, OpSize; // if >=u, R16 = [mem16] -def CMOVAE32rr: I<0x43, MRMSrcReg>, TB, // if >=u, R32 = R32 - II<(ops R32:$dst, R32:$src1, R32:$src2), "cmovae $dst, $src2">; +def CMOVAE32rr: I<0x43, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), + "cmovae $dst, $src2">, TB; // if >=u, R32 = R32 def CMOVAE32rm: Im32<"cmovae", 0x43, MRMSrcMem>, TB; // if >=u, R32 = [mem32] -def CMOVE16rr : I<0x44, MRMSrcReg>, TB, OpSize, // if ==, R16 = R16 - II<(ops R16:$dst, R16:$src1, R16:$src2), "cmove $dst, $src2">; +def CMOVE16rr : I<0x44, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), + "cmove $dst, $src2">, TB, OpSize; // if ==, R16 = R16 def CMOVE16rm : Im16<"cmove", 0x44, MRMSrcMem>, TB, OpSize; // if ==, R16 = [mem16] -def CMOVE32rr : I<0x44, MRMSrcReg>, TB, // if ==, R32 = R32 - II<(ops R32:$dst, R32:$src1, R32:$src2), "cmove $dst, $src2">; +def CMOVE32rr : I<0x44, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), + "cmove $dst, $src2">, TB; // if ==, R32 = R32 def CMOVE32rm : Im32<"cmove", 0x44, MRMSrcMem>, TB; // if ==, R32 = [mem32] -def CMOVNE16rr: I<0x45, MRMSrcReg>, TB, OpSize, // if !=, R16 = R16 - II<(ops R16:$dst, R16:$src1, R16:$src2), "cmovne $dst, $src2">; +def CMOVNE16rr: I<0x45, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), + "cmovne $dst, $src2">, TB, OpSize; // if !=, R16 = R16 def CMOVNE16rm: Im16<"cmovne",0x45, MRMSrcMem>, TB, OpSize; // if !=, R16 = [mem16] -def CMOVNE32rr: I<0x45, MRMSrcReg>, TB, // if !=, R32 = R32 - II<(ops R32:$dst, R32:$src1, R32:$src2), "cmovne $dst, $src2">; +def CMOVNE32rr: I<0x45, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), + "cmovne $dst, $src2">, TB; // if !=, R32 = R32 def CMOVNE32rm: Im32<"cmovne",0x45, MRMSrcMem>, TB; // if !=, R32 = [mem32] -def CMOVBE16rr: I<0x46, MRMSrcReg>, TB, OpSize, // if <=u, R16 = R16 - II<(ops R16:$dst, R16:$src1, R16:$src2), "cmovbe $dst, $src2">; +def CMOVBE16rr: I<0x46, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), + "cmovbe $dst, $src2">, TB, OpSize; // if <=u, R16 = R16 def CMOVBE16rm: Im16<"cmovbe",0x46, MRMSrcMem>, TB, OpSize; // if <=u, R16 = [mem16] -def CMOVBE32rr: I<0x46, MRMSrcReg>, TB, // if <=u, R32 = R32 - II<(ops R32:$dst, R32:$src1, R32:$src2), "cmovbe $dst, $src2">; +def CMOVBE32rr: I<0x46, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), + "cmovbe $dst, $src2">, TB; // if <=u, R32 = R32 def CMOVBE32rm: Im32<"cmovbe",0x46, MRMSrcMem>, TB; // if <=u, R32 = [mem32] -def CMOVA16rr : I<0x47, MRMSrcReg>, TB, OpSize, // if >u, R16 = R16 - II<(ops R16:$dst, R16:$src1, R16:$src2), "cmova $dst, $src2">; +def CMOVA16rr : I<0x47, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), + "cmova $dst, $src2">, TB, OpSize; // if >u, R16 = R16 def CMOVA16rm : Im16<"cmova", 0x47, MRMSrcMem>, TB, OpSize; // if >u, R16 = [mem16] -def CMOVA32rr : I<0x47, MRMSrcReg>, TB, // if >u, R32 = R32 - II<(ops R32:$dst, R32:$src1, R32:$src2), "cmova $dst, $src2">; +def CMOVA32rr : I<0x47, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), + "cmova $dst, $src2">, TB; // if >u, R32 = R32 def CMOVA32rm : Im32<"cmova", 0x47, MRMSrcMem>, TB; // if >u, R32 = [mem32] -def CMOVS16rr : I<0x48, MRMSrcReg>, TB, OpSize, // if signed, R16 = R16 - II<(ops R16:$dst, R16:$src1, R16:$src2), "cmovs $dst, $src2">; +def CMOVS16rr : I<0x48, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), + "cmovs $dst, $src2">, TB, OpSize; // if signed, R16 = R16 def CMOVS16rm : Im16<"cmovs", 0x48, MRMSrcMem>, TB, OpSize; // if signed, R16 = [mem16] -def CMOVS32rr : I<0x48, MRMSrcReg>, TB, // if signed, R32 = R32 - II<(ops R32:$dst, R32:$src1, R32:$src2), "cmovs $dst, $src2">; +def CMOVS32rr : I<0x48, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), + "cmovs $dst, $src2">, TB; // if signed, R32 = R32 def CMOVS32rm : Im32<"cmovs", 0x48, MRMSrcMem>, TB; // if signed, R32 = [mem32] -def CMOVNS16rr: I<0x49, MRMSrcReg>, TB, OpSize, // if !signed, R16 = R16 - II<(ops R16:$dst, R16:$src1, R16:$src2), "cmovns $dst, $src2">; +def CMOVNS16rr: I<0x49, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), + "cmovns $dst, $src2">, TB, OpSize; // if !signed, R16 = R16 def CMOVNS16rm: Im16<"cmovns",0x49, MRMSrcMem>, TB, OpSize; // if !signed, R16 = [mem16] -def CMOVNS32rr: I<0x49, MRMSrcReg>, TB, // if !signed, R32 = R32 - II<(ops R32:$dst, R32:$src1, R32:$src2), "cmovns $dst, $src2">; +def CMOVNS32rr: I<0x49, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), + "cmovns $dst, $src2">, TB; // if !signed, R32 = R32 def CMOVNS32rm: Im32<"cmovns",0x49, MRMSrcMem>, TB; // if !signed, R32 = [mem32] -def CMOVL16rr : I<0x4C, MRMSrcReg>, TB, OpSize, // if ; +def CMOVL16rr : I<0x4C, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), + "cmovl $dst, $src2">, TB, OpSize; // if , TB, OpSize; // if , TB, // if ; +def CMOVL32rr : I<0x4C, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), + "cmovl $dst, $src2">, TB; // if , TB; // if , TB, OpSize, // if >=s, R16 = R16 - II<(ops R16:$dst, R16:$src1, R16:$src2), "cmovge $dst, $src2">; +def CMOVGE16rr: I<0x4D, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), + "cmovge $dst, $src2">, TB, OpSize; // if >=s, R16 = R16 def CMOVGE16rm: Im16<"cmovge",0x4D, MRMSrcMem>, TB, OpSize; // if >=s, R16 = [mem16] -def CMOVGE32rr: I<0x4D, MRMSrcReg>, TB, // if >=s, R32 = R32 - II<(ops R32:$dst, R32:$src1, R32:$src2), "cmovge $dst, $src2">; +def CMOVGE32rr: I<0x4D, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), + "cmovge $dst, $src2">, TB; // if >=s, R32 = R32 def CMOVGE32rm: Im32<"cmovge",0x4D, MRMSrcMem>, TB; // if >=s, R32 = [mem32] -def CMOVLE16rr: I<0x4E, MRMSrcReg>, TB, OpSize, // if <=s, R16 = R16 - II<(ops R16:$dst, R16:$src1, R16:$src2), "cmovle $dst, $src2">; +def CMOVLE16rr: I<0x4E, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), + "cmovle $dst, $src2">, TB, OpSize; // if <=s, R16 = R16 def CMOVLE16rm: Im16<"cmovle",0x4E, MRMSrcMem>, TB, OpSize; // if <=s, R16 = [mem16] -def CMOVLE32rr: I<0x4E, MRMSrcReg>, TB, // if <=s, R32 = R32 - II<(ops R32:$dst, R32:$src1, R32:$src2), "cmovle $dst, $src2">; +def CMOVLE32rr: I<0x4E, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), + "cmovle $dst, $src2">, TB; // if <=s, R32 = R32 def CMOVLE32rm: Im32<"cmovle",0x4E, MRMSrcMem>, TB; // if <=s, R32 = [mem32] -def CMOVG16rr : I<0x4F, MRMSrcReg>, TB, OpSize, // if >s, R16 = R16 - II<(ops R16:$dst, R16:$src1, R16:$src2), "cmovg $dst, $src2">; +def CMOVG16rr : I<0x4F, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), + "cmovg $dst, $src2">, TB, OpSize; // if >s, R16 = R16 def CMOVG16rm : Im16<"cmovg", 0x4F, MRMSrcMem>, TB, OpSize; // if >s, R16 = [mem16] -def CMOVG32rr : I<0x4F, MRMSrcReg>, TB, // if >s, R32 = R32 - II<(ops R32:$dst, R32:$src1, R32:$src2), "cmovg $dst, $src2">; +def CMOVG32rr : I<0x4F, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), + "cmovg $dst, $src2">, TB; // if >s, R32 = R32 def CMOVG32rm : Im32<"cmovg", 0x4F, MRMSrcMem>, TB; // if >s, R32 = [mem32] // unary instructions -def NEG8r : I<0xF6, MRM3r>, // R8 = -R8 = 0-R8 - II<(ops R8:$dst, R8:$src), "neg $dst">; -def NEG16r : I<0xF7, MRM3r>, OpSize, // R16 = -R16 = 0-R16 - II<(ops R16:$dst, R16:$src), "neg $dst">; -def NEG32r : I<0xF7, MRM3r>, // R32 = -R32 = 0-R32 - II<(ops R32:$dst, R32:$src), "neg $dst">; +def NEG8r : I<0xF6, MRM3r, (ops R8 :$dst, R8 :$src), "neg $dst">; +def NEG16r : I<0xF7, MRM3r, (ops R16:$dst, R16:$src), "neg $dst">, OpSize; +def NEG32r : I<0xF7, MRM3r, (ops R32:$dst, R32:$src), "neg $dst">; 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<0xF6, MRM2r>, // R8 = ~R8 = R8^-1 - II<(ops R8:$dst, R8:$src), "not $dst">; -def NOT16r : I<0xF7, MRM2r>, OpSize, // R16 = ~R16 = R16^-1 - II<(ops R16:$dst, R16:$src), "not $dst">; -def NOT32r : I<0xF7, MRM2r>, // R32 = ~R32 = R32^-1 - II<(ops R32:$dst, R32:$src), "not $dst">; +def NOT8r : I<0xF6, MRM2r, (ops R8 :$dst, R8 :$src), "not $dst">; +def NOT16r : I<0xF7, MRM2r, (ops R16:$dst, R16:$src), "not $dst">, OpSize; +def NOT32r : I<0xF7, MRM2r, (ops R32:$dst, R32:$src), "not $dst">; 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<0xFE, MRM0r>, // ++R8 - II<(ops R8:$dst, R8:$src), "inc $dst">; -def INC16r : I<0xFF, MRM0r>, OpSize, // ++R16 - II<(ops R16:$dst, R16:$src), "inc $dst">; -def INC32r : I<0xFF, MRM0r>, // ++R32 - II<(ops R32:$dst, R32:$src), "inc $dst">; +def INC8r : I<0xFE, MRM0r, (ops R8 :$dst, R8 :$src), "inc $dst">; +def INC16r : I<0xFF, MRM0r, (ops R16:$dst, R16:$src), "inc $dst">, OpSize; +def INC32r : I<0xFF, MRM0r, (ops R32:$dst, R32:$src), "inc $dst">; 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<0xFE, MRM1r>, // --R8 - II<(ops R8:$dst, R8:$src), "dec $dst">; -def DEC16r : I<0xFF, MRM1r>, OpSize, // --R16 - II<(ops R16:$dst, R16:$src), "dec $dst">; -def DEC32r : I<0xFF, MRM1r>, // --R32 - II<(ops R32:$dst, R32:$src), "dec $dst">; +def DEC8r : I<0xFE, MRM1r, (ops R8 :$dst, R8 :$src), "dec $dst">; +def DEC16r : I<0xFF, MRM1r, (ops R16:$dst, R16:$src), "dec $dst">, OpSize; +def DEC32r : I<0xFF, MRM1r, (ops R32:$dst, R32:$src), "dec $dst">; 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<0x20, MRMDestReg>, - II<(ops R8:$dst, R8:$src1, R8:$src2), "and $dst, $src2">; -def AND16rr : I<0x21, MRMDestReg>, OpSize, - II<(ops R16:$dst, R16:$src1, R16:$src2), "and $dst, $src2">; -def AND32rr : I<0x21, MRMDestReg>, - II<(ops R32:$dst, R32:$src1, R32:$src2), "and $dst, $src2">; +def AND8rr : I<0x20, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "and $dst, $src2">; +def AND16rr : I<0x21, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "and $dst, $src2">, OpSize; +def AND32rr : I<0x21, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "and $dst, $src2">; 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 @@ -506,12 +483,9 @@ def AND32mi8 : Im32i8<"and", 0x83, MRM4m >; // [mem32] &= imm8 -def OR8rr : I<0x08, MRMDestReg>, - II<(ops R8:$dst, R8:$src1, R8:$src2), "or $dst, $src2">; -def OR16rr : I<0x09, MRMDestReg>, OpSize, - II<(ops R16:$dst, R16:$src1, R16:$src2), "or $dst, $src2">; -def OR32rr : I<0x09, MRMDestReg>, - II<(ops R32:$dst, R32:$src1, R32:$src2), "or $dst, $src2">; +def OR8rr : I<0x08, MRMDestReg, (ops R8:$dst, R8:$src1, R8:$src2), "or $dst, $src2">; +def OR16rr : I<0x09, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "or $dst, $src2">, OpSize; +def OR32rr : I<0x09, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "or $dst, $src2">; 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 @@ -532,12 +506,9 @@ def OR32mi8 : Im32i8<"or" , 0x83, MRM1m >; // [mem32] |= imm8 -def XOR8rr : I<0x30, MRMDestReg>, - II<(ops R8:$dst, R8:$src1, R8:$src2), "xor $dst, $src2">; -def XOR16rr : I<0x31, MRMDestReg>, OpSize, - II<(ops R16:$dst, R16:$src1, R16:$src2), "xor $dst, $src2">; -def XOR32rr : I<0x31, MRMDestReg>, - II<(ops R32:$dst, R32:$src1, R32:$src2), "xor $dst, $src2">; +def XOR8rr : I<0x30, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "xor $dst, $src2">; +def XOR16rr : I<0x31, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "xor $dst, $src2">, OpSize; +def XOR32rr : I<0x31, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "xor $dst, $src2">; 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 @@ -560,12 +531,9 @@ // Shift instructions // FIXME: provide shorter instructions when imm8 == 1 let Uses = [CL], printImplicitUsesAfter = 1 in { - def SHL8rCL : I<0xD2, MRM4r> , // R8 <<= cl - II<(ops R8:$dst, R8:$src), "shl $dst, %CL">; - def SHL16rCL : I<0xD3, MRM4r>, OpSize, // R16 <<= cl - II<(ops R16:$dst, R16:$src), "shl $dst, %CL">; - def SHL32rCL : I<0xD3, MRM4r> , // R32 <<= cl - II<(ops R32:$dst, R32:$src), "shl $dst, %CL">; + def SHL8rCL : I<0xD2, MRM4r, (ops R8 :$dst, R8 :$src), "shl $dst, %CL">; + def SHL16rCL : I<0xD3, MRM4r, (ops R16:$dst, R16:$src), "shl $dst, %CL">, OpSize; + def SHL32rCL : I<0xD3, MRM4r, (ops R32:$dst, R32:$src), "shl $dst, %CL">; def SHL8mCL : Im8 <"shl", 0xD2, MRM4m > ; // [mem8] <<= cl def SHL16mCL : Im16 <"shl", 0xD3, MRM4m >, OpSize; // [mem16] <<= cl def SHL32mCL : Im32 <"shl", 0xD3, MRM4m > ; // [mem32] <<= cl @@ -579,12 +547,9 @@ def SHL32mi : Im32i8<"shl", 0xC1, MRM4m >; // [mem32] <<= imm8 let Uses = [CL], printImplicitUsesAfter = 1 in { - def SHR8rCL : I<0xD2, MRM5r> , // R8 >>= cl - II<(ops R8:$dst, R8:$src), "shr $dst, %CL">; - def SHR16rCL : I<0xD3, MRM5r>, OpSize, // R16 >>= cl - II<(ops R16:$dst, R16:$src), "shr $dst, %CL">; - def SHR32rCL : I<0xD3, MRM5r> , // R32 >>= cl - II<(ops R32:$dst, R32:$src), "shr $dst, %CL">; + def SHR8rCL : I<0xD2, MRM5r, (ops R8 :$dst, R8 :$src), "shr $dst, %CL">; + def SHR16rCL : I<0xD3, MRM5r, (ops R16:$dst, R16:$src), "shr $dst, %CL">, OpSize; + def SHR32rCL : I<0xD3, MRM5r, (ops R32:$dst, R32:$src), "shr $dst, %CL">; def SHR8mCL : Im8 <"shr", 0xD2, MRM5m > ; // [mem8] >>= cl def SHR16mCL : Im16 <"shr", 0xD3, MRM5m >, OpSize; // [mem16] >>= cl def SHR32mCL : Im32 <"shr", 0xD3, MRM5m > ; // [mem32] >>= cl @@ -598,12 +563,9 @@ def SHR32mi : Im32i8<"shr", 0xC1, MRM5m >; // [mem32] >>= imm8 let Uses = [CL], printImplicitUsesAfter = 1 in { - def SAR8rCL : I<0xD2, MRM7r>, // R8 >>>= cl - II<(ops R8:$dst, R8:$src), "sar $dst, %CL">; - def SAR16rCL : I<0xD3, MRM7r>, OpSize, // R16 >>>= cl - II<(ops R16:$dst, R16:$src), "sar $dst, %CL">; - def SAR32rCL : I<0xD3, MRM7r>, // R32 >>>= cl - II<(ops R32:$dst, R32:$src), "sar $dst, %CL">; + def SAR8rCL : I<0xD2, MRM7r, (ops R8 :$dst, R8 :$src), "sar $dst, %CL">; + def SAR16rCL : I<0xD3, MRM7r, (ops R16:$dst, R16:$src), "sar $dst, %CL">, OpSize; + def SAR32rCL : I<0xD3, MRM7r, (ops R32:$dst, R32:$src), "sar $dst, %CL">; def SAR8mCL : Im8 <"sar", 0xD2, MRM7m > ; // [mem8] >>>= cl def SAR16mCL : Im16 <"sar", 0xD3, MRM7m >, OpSize; // [mem16] >>>= cl def SAR32mCL : Im32 <"sar", 0xD3, MRM7m > ; // [mem32] >>>= cl @@ -617,11 +579,9 @@ def SAR32mi : Im32i8<"sar", 0xC1, MRM7m >; // [mem32] >>>= imm8 let Uses = [CL], printImplicitUsesAfter = 1 in { - def SHLD32rrCL : I<0xA5, MRMDestReg>, TB, // R32 <<= R32,R32 cl - II<(ops R32:$dst, R32:$src1, R32:$src2), "shld $dst, $src2, %CL">; + def SHLD32rrCL : I<0xA5, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "shld $dst, $src2, %CL">, TB; def SHLD32mrCL : Im32 <"shld", 0xA5, MRMDestMem>, TB; // [mem32] <<= [mem32],R32 cl - def SHRD32rrCL : I<0xAD, MRMDestReg>, TB, // R32 >>= R32,R32 cl - II<(ops R32:$dst, R32:$src1, R32:$src2), "shrd $dst, $src2, %CL">; + def SHRD32rrCL : I<0xAD, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "shrd $dst, $src2, %CL">, TB; def SHRD32mrCL : Im32 <"shrd", 0xAD, MRMDestMem>, TB; // [mem32] >>= [mem32],R32 cl } @@ -632,9 +592,9 @@ // Arithmetic... -def ADD8rr : I<0x00, MRMDestReg>, II<(ops R8:$dst, R8:$src1, R8:$src2), "add $dst, $src2">; -def ADD16rr : I<0x01, MRMDestReg>, OpSize, II<(ops R16:$dst, R16:$src1, R16:$src2), "add $dst, $src2">; -def ADD32rr : I<0x01, MRMDestReg>, II<(ops R32:$dst, R32:$src1, R32:$src2), "add $dst, $src2">; +def ADD8rr : I<0x00, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "add $dst, $src2">; +def ADD16rr : I<0x01, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "add $dst, $src2">, OpSize; +def ADD32rr : I<0x01, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "add $dst, $src2">; 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 @@ -654,8 +614,7 @@ def ADD16mi8 : Im16i8<"add", 0x83, MRM0m >, OpSize; // [mem16] += I8 def ADD32mi8 : Im32i8<"add", 0x83, MRM0m >; // [mem32] += I8 -def ADC32rr : I<0x11, MRMDestReg>, // R32 += R32+Carry - II<(ops R32:$dst, R32:$src1, R32:$src2), "adc $dst, $src2">; +def ADC32rr : I<0x11, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "adc $dst, $src2">; def ADC32mr : Im32 <"adc", 0x11, MRMDestMem>; // [mem32] += R32+Carry def ADC32rm : Im32 <"adc", 0x13, MRMSrcMem >; // R32 += [mem32]+Carry def ADC32ri : Ii32 <0x81, MRM2r, (ops R32:$dst, R32:$src1, i32imm:$src2), "adc $dst, $src2">; // R32 += I32+Carry @@ -663,9 +622,9 @@ def ADC32mi : Im32i32<"adc", 0x81, MRM2m >; // [mem32] += I32+Carry def ADC32mi8 : Im32i8 <"adc", 0x83, MRM2m >; // [mem32] += I8+Carry -def SUB8rr : I<0x28, MRMDestReg>, II<(ops R8:$dst, R8:$src1, R8:$src2), "sub $dst, $src2">; -def SUB16rr : I<0x29, MRMDestReg>, OpSize, II<(ops R16:$dst, R16:$src1, R16:$src2), "sub $dst, $src2">; -def SUB32rr : I<0x29, MRMDestReg>, II<(ops R32:$dst, R32:$src1, R32:$src2), "sub $dst, $src2">; +def SUB8rr : I<0x28, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "sub $dst, $src2">; +def SUB16rr : I<0x29, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "sub $dst, $src2">, OpSize; +def SUB32rr : I<0x29, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "sub $dst, $src2">; 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 @@ -685,8 +644,7 @@ def SUB16mi8 : Im16i8<"sub", 0x83, MRM5m >, OpSize; // [mem16] -= I8 def SUB32mi8 : Im32i8<"sub", 0x83, MRM5m >; // [mem32] -= I8 -def SBB32rr : I<0x19, MRMDestReg>, // R32 -= R32+Carry - II<(ops R32:$dst, R32:$src1, R32:$src2), "adc $dst, $src2">; +def SBB32rr : I<0x19, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "adc $dst, $src2">; def SBB32mr : Im32 <"sbb", 0x19, MRMDestMem>; // [mem32] -= R32+Carry def SBB32rm : Im32 <"sbb", 0x1B, MRMSrcMem >; // R32 -= [mem32]+Carry def SBB32ri : Ii32 <0x81, MRM3r, (ops R32:$dst, R32:$src1, i32imm:$src2), "sbb $dst, $src2">; // R32 -= I32+Carry @@ -694,10 +652,8 @@ def SBB32mi : Im32i32<"sbb", 0x81, MRM3m >; // [mem32] -= I32+Carry def SBB32mi8 : Im32i8 <"sbb", 0x83, MRM3m >; // [mem32] -= I8+Carry -def IMUL16rr : I<0xAF, MRMSrcReg>, TB, OpSize, - II<(ops R16:$dst, R16:$src1, R16:$src2), "imul $dst, $src2">; -def IMUL32rr : I<0xAF, MRMSrcReg>, TB, - II<(ops R32:$dst, R32:$src1, R32:$src2), "imul $dst, $src2">; +def IMUL16rr : I<0xAF, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "imul $dst, $src2">, TB, OpSize; +def IMUL32rr : I<0xAF, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "imul $dst, $src2">, TB; def IMUL16rm : Im16 <"imul", 0xAF, MRMSrcMem>, TB, OpSize; def IMUL32rm : Im32 <"imul", 0xAF, MRMSrcMem>, TB ; @@ -715,12 +671,9 @@ //===----------------------------------------------------------------------===// // Test instructions are just like AND, except they don't generate a result. -def TEST8rr : I<0x84, MRMDestReg>, // flags = R8 & R8 - II<(ops R8:$src1, R8:$src2), "test $src1, $src2">; -def TEST16rr : I<0x85, MRMDestReg>, OpSize, // flags = R16 & R16 - II<(ops R16:$src1, R16:$src2), "test $src1, $src2">; -def TEST32rr : I<0x85, MRMDestReg>, // flags = R32 & R32 - II<(ops R32:$src1, R32:$src2), "test $src1, $src2">; +def TEST8rr : I<0x84, MRMDestReg, (ops R8:$src1, R8:$src2), "test $src1, $src2">; +def TEST16rr : I<0x85, MRMDestReg, (ops R16:$src1, R16:$src2), "test $src1, $src2">, OpSize; +def TEST32rr : I<0x85, MRMDestReg, (ops R32:$src1, R32:$src2), "test $src1, $src2">; 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 @@ -738,58 +691,40 @@ // Condition code ops, incl. set if equal/not equal/... -def SAHF : I<0x9E, RawFrm>, Imp<[AH],[]>, // flags = AH - II<(ops), "sahf">; -def LAHF : I<0x9F, RawFrm>, Imp<[],[AH]>, // AH = flags - II<(ops), "lahf">; +def SAHF : I<0x9E, RawFrm, (ops), "sahf">, Imp<[AH],[]>; // flags = AH +def LAHF : I<0x9F, RawFrm, (ops), "lahf">, Imp<[],[AH]>; // AH = flags -def SETBr : I<0x92, MRM0r>, TB, // R8 = < unsign - II<(ops R8:$dst), "setb $dst">; +def SETBr : I<0x92, MRM0r, (ops R8:$dst), "setb $dst">, TB; // R8 = < unsign def SETBm : Im8<"setb" , 0x92, MRM0m>, TB; // [mem8] = < unsign -def SETAEr : I<0x93, MRM0r>, TB, // R8 = >= unsign - II<(ops R8:$dst), "setae $dst">; +def SETAEr : I<0x93, MRM0r, (ops R8:$dst), "setae $dst">, TB; // R8 = >= unsign def SETAEm : Im8<"setae", 0x93, MRM0m>, TB; // [mem8] = >= unsign -def SETEr : I<0x94, MRM0r>, TB, // R8 = == - II<(ops R8:$dst), "sete $dst">; +def SETEr : I<0x94, MRM0r, (ops R8:$dst), "sete $dst">, TB; // R8 = == def SETEm : Im8<"sete" , 0x94, MRM0m>, TB; // [mem8] = == -def SETNEr : I<0x95, MRM0r>, TB, // R8 = != - II<(ops R8:$dst), "setne $dst">; +def SETNEr : I<0x95, MRM0r, (ops R8:$dst), "setne $dst">, TB; // R8 = != def SETNEm : Im8<"setne", 0x95, MRM0m>, TB; // [mem8] = != -def SETBEr : I<0x96, MRM0r>, TB, // R8 = <= unsign - II<(ops R8:$dst), "setbe $dst">; +def SETBEr : I<0x96, MRM0r, (ops R8:$dst), "setbe $dst">, TB; // R8 = <= unsign def SETBEm : Im8<"setbe", 0x96, MRM0m>, TB; // [mem8] = <= unsign -def SETAr : I<0x97, MRM0r>, TB, // R8 = > signed - II<(ops R8:$dst), "seta $dst">; +def SETAr : I<0x97, MRM0r, (ops R8:$dst), "seta $dst">, TB; // R8 = > signed def SETAm : Im8<"seta" , 0x97, MRM0m>, TB; // [mem8] = > signed -def SETSr : I<0x98, MRM0r>, TB, // R8 = - II<(ops R8:$dst), "sets $dst">; +def SETSr : I<0x98, MRM0r, (ops R8:$dst), "sets $dst">, TB; // R8 = def SETSm : Im8<"sets" , 0x98, MRM0m>, TB; // [mem8] = -def SETNSr : I<0x99, MRM0r>, TB, // R8 = ! - II<(ops R8:$dst), "setns $dst">; +def SETNSr : I<0x99, MRM0r, (ops R8:$dst), "setns $dst">, TB; // R8 = ! def SETNSm : Im8<"setns", 0x99, MRM0m>, TB; // [mem8] = ! -def SETPr : I<0x9A, MRM0r>, TB, // R8 = parity - II<(ops R8:$dst), "setp $dst">; +def SETPr : I<0x9A, MRM0r, (ops R8:$dst), "setp $dst">, TB; // R8 = parity def SETPm : Im8<"setp" , 0x9A, MRM0m>, TB; // [mem8] = parity -def SETLr : I<0x9C, MRM0r>, TB, // R8 = < signed - II<(ops R8:$dst), "setl $dst">; +def SETLr : I<0x9C, MRM0r, (ops R8:$dst), "setl $dst">, TB; // R8 = < signed def SETLm : Im8<"setl" , 0x9C, MRM0m>, TB; // [mem8] = < signed -def SETGEr : I<0x9D, MRM0r>, TB, // R8 = >= signed - II<(ops R8:$dst), "setge $dst">; +def SETGEr : I<0x9D, MRM0r, (ops R8:$dst), "setge $dst">, TB; // R8 = >= signed def SETGEm : Im8<"setge", 0x9D, MRM0m>, TB; // [mem8] = >= signed -def SETLEr : I<0x9E, MRM0r>, TB, // R8 = <= signed - II<(ops R8:$dst), "setle $dst">; +def SETLEr : I<0x9E, MRM0r, (ops R8:$dst), "setle $dst">, TB; // R8 = <= signed def SETLEm : Im8<"setle", 0x9E, MRM0m>, TB; // [mem8] = <= signed -def SETGr : I<0x9F, MRM0r>, TB, // R8 = < signed - II<(ops R8:$dst), "setg $dst">; +def SETGr : I<0x9F, MRM0r, (ops R8:$dst), "setg $dst">, TB; // R8 = < signed def SETGm : Im8<"setg" , 0x9F, MRM0m>, TB; // [mem8] = < signed // Integer comparisons -def CMP8rr : I<0x38, MRMDestReg>, // compare R8, R8 - II<(ops R8:$src1, R8:$src2), "cmp $src1, $src2">; -def CMP16rr : I<0x39, MRMDestReg>, OpSize, // compare R16, R16 - II<(ops R16:$src1, R16:$src2), "cmp $src1, $src2">; -def CMP32rr : I<0x39, MRMDestReg>, // compare R32, R32 - II<(ops R32:$src1, R32:$src2), "cmp $src1, $src2">; +def CMP8rr : I<0x38, MRMDestReg, (ops R8 :$src1, R8 :$src2), "cmp $src1, $src2">; +def CMP16rr : I<0x39, MRMDestReg, (ops R16:$src1, R16:$src2), "cmp $src1, $src2">, OpSize; +def CMP32rr : I<0x39, MRMDestReg, (ops R32:$src1, R32:$src2), "cmp $src1, $src2">; 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 @@ -804,22 +739,16 @@ def CMP32mi : Im32i32<"cmp", 0x81, MRM7m >; // compare [mem32], imm32 // Sign/Zero extenders -def MOVSX16rr8 : I<0xBE, MRMSrcReg>, TB, OpSize, // R16 = signext(R8) - II<(ops R16:$dst, R8:$src), "movsx $dst, $src">; -def MOVSX32rr8 : I<0xBE, MRMSrcReg>, TB, // R32 = signext(R8) - II<(ops R32:$dst, R8:$src), "movsx $dst, $src">; -def MOVSX32rr16: I<0xBF, MRMSrcReg>, TB, // R32 = signext(R16) - II<(ops R32:$dst, R16:$src), "movsx $dst, $src">; +def MOVSX16rr8 : I<0xBE, MRMSrcReg, (ops R16:$dst, R8 :$src), "movsx $dst, $src">, TB, OpSize; +def MOVSX32rr8 : I<0xBE, MRMSrcReg, (ops R32:$dst, R8 :$src), "movsx $dst, $src">, TB; +def MOVSX32rr16: I<0xBF, MRMSrcReg, (ops R32:$dst, R16:$src), "movsx $dst, $src">, TB; 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<0xB6, MRMSrcReg>, TB, OpSize, // R16 = zeroext(R8) - II<(ops R16:$dst, R8:$src), "movzx $dst, $src">; -def MOVZX32rr8 : I<0xB6, MRMSrcReg>, TB, // R32 = zeroext(R8) - II<(ops R32:$dst, R8:$src), "movzx $dst, $src">; -def MOVZX32rr16: I<0xB7, MRMSrcReg>, TB, // R32 = zeroext(R16) - II<(ops R32:$dst, R16:$src), "movzx $dst, $src">; +def MOVZX16rr8 : I<0xB6, MRMSrcReg, (ops R16:$dst, R8 :$src), "movzx $dst, $src">, TB, OpSize; +def MOVZX32rr8 : I<0xB6, MRMSrcReg, (ops R32:$dst, R8 :$src), "movzx $dst, $src">, TB; +def MOVZX32rr16: I<0xB7, MRMSrcReg, (ops R32:$dst, R16:$src), "movzx $dst, $src">, TB; 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]) @@ -951,59 +880,57 @@ II<(ops), "ftst">; // Binary arithmetic operations... -class FPST0rInst o> : I, D8 { +class FPST0rInst o, dag ops, string asm> : I, D8 { list Uses = [ST0]; list Defs = [ST0]; } -class FPrST0Inst o> : I, DC { +class FPrST0Inst o, dag ops, string asm> : I, DC { list Uses = [ST0]; } -class FPrST0PInst o> : I, DE { +class FPrST0PInst o, dag ops, string asm> : I, DE { list Uses = [ST0]; } -def FADDST0r : FPST0rInst <0xC0>, II<(ops RST:$op), "fadd $op">; -def FADDrST0 : FPrST0Inst <0xC0>, II<(ops RST:$op), "fadd $op, %ST(0)">; -def FADDPrST0 : FPrST0PInst<0xC0>, II<(ops RST:$op), "faddp $op">; - -def FSUBRST0r : FPST0rInst <0xE8>, II<(ops RST:$op), "fsubr $op">; -def FSUBrST0 : FPrST0Inst <0xE8>, II<(ops RST:$op), "fsub $op, %ST(0)">; -def FSUBPrST0 : FPrST0PInst<0xE8>, II<(ops RST:$op), "fsubp $op">; - -def FSUBST0r : FPST0rInst <0xE0>, II<(ops RST:$op), "fsub $op">; -def FSUBRrST0 : FPrST0Inst <0xE0>, II<(ops RST:$op), "fsubr $op, %ST(0)">; -def FSUBRPrST0 : FPrST0PInst<0xE0>, II<(ops RST:$op), "fsubrp $op">; - -def FMULST0r : FPST0rInst <0xC8>, II<(ops RST:$op), "fmul $op">; -def FMULrST0 : FPrST0Inst <0xC8>, II<(ops RST:$op), "fmul $op, %ST(0)">; -def FMULPrST0 : FPrST0PInst<0xC8>, II<(ops RST:$op), "fmulp $op">; - -def FDIVRST0r : FPST0rInst <0xF8>, II<(ops RST:$op), "fdivr $op">; -def FDIVrST0 : FPrST0Inst <0xF8>, II<(ops RST:$op), "fdiv $op, %ST(0)">; -def FDIVPrST0 : FPrST0PInst<0xF8>, II<(ops RST:$op), "fdivp $op">; - -def FDIVST0r : FPST0rInst <0xF0>, II<(ops RST:$op), "fdiv $op">; // ST(0) = ST(0) / ST(i) -def FDIVRrST0 : FPrST0Inst <0xF0>, II<(ops RST:$op), "fdivr $op, %ST(0)">; // ST(i) = ST(0) / ST(i) -def FDIVRPrST0 : FPrST0PInst<0xF0>, II<(ops RST:$op), "fdivrp $op">; // ST(i) = ST(0) / ST(i), pop +def FADDST0r : FPST0rInst <0xC0, (ops RST:$op), "fadd $op">; +def FADDrST0 : FPrST0Inst <0xC0, (ops RST:$op), "fadd $op, %ST(0)">; +def FADDPrST0 : FPrST0PInst<0xC0, (ops RST:$op), "faddp $op">; + +def FSUBRST0r : FPST0rInst <0xE8, (ops RST:$op), "fsubr $op">; +def FSUBrST0 : FPrST0Inst <0xE8, (ops RST:$op), "fsub $op, %ST(0)">; +def FSUBPrST0 : FPrST0PInst<0xE8, (ops RST:$op), "fsubp $op">; + +def FSUBST0r : FPST0rInst <0xE0, (ops RST:$op), "fsub $op">; +def FSUBRrST0 : FPrST0Inst <0xE0, (ops RST:$op), "fsubr $op, %ST(0)">; +def FSUBRPrST0 : FPrST0PInst<0xE0, (ops RST:$op), "fsubrp $op">; + +def FMULST0r : FPST0rInst <0xC8, (ops RST:$op), "fmul $op">; +def FMULrST0 : FPrST0Inst <0xC8, (ops RST:$op), "fmul $op, %ST(0)">; +def FMULPrST0 : FPrST0PInst<0xC8, (ops RST:$op), "fmulp $op">; + +def FDIVRST0r : FPST0rInst <0xF8, (ops RST:$op), "fdivr $op">; +def FDIVrST0 : FPrST0Inst <0xF8, (ops RST:$op), "fdiv $op, %ST(0)">; +def FDIVPrST0 : FPrST0PInst<0xF8, (ops RST:$op), "fdivp $op">; + +def FDIVST0r : FPST0rInst <0xF0, (ops RST:$op), "fdiv $op">; // ST(0) = ST(0) / ST(i) +def FDIVRrST0 : FPrST0Inst <0xF0, (ops RST:$op), "fdivr $op, %ST(0)">; // ST(i) = ST(0) / ST(i) +def FDIVRPrST0 : FPrST0PInst<0xF0, (ops RST:$op), "fdivrp $op">; // ST(i) = ST(0) / ST(i), pop // Floating point compares def FUCOMr : FPI<"", 0xE0, AddRegFrm, CompareFP>, DD, Imp<[ST0],[]>, // FPSW = compare ST(0) with ST(i) II<(ops RST:$reg), "fucom $reg">; -def FUCOMPr : I<0xE8, AddRegFrm>, DD, Imp<[ST0],[]>, // FPSW = compare ST(0) with ST(i), pop - II<(ops RST:$reg), "fucomp $reg">; -def FUCOMPPr : I<0xE9, RawFrm >, DA, Imp<[ST0],[]>, // compare ST(0) with ST(1), pop, pop - II<(ops), "fucompp">; - +def FUCOMPr : I<0xE8, AddRegFrm, (ops RST:$reg), + "fucomp $reg">, DD, Imp<[ST0],[]>; // FPSW = compare ST(0) with ST(i), pop +def FUCOMPPr : I<0xE9, RawFrm, (ops), + "fucompp">, DA, Imp<[ST0],[]>; // compare ST(0) with ST(1), pop, pop def FUCOMIr : FPI<"", 0xE8, AddRegFrm, CompareFP>, DB, Imp<[ST0],[]>, // CC = compare ST(0) with ST(i) II<(ops RST:$reg), "fucomi %ST(0), $reg">; -def FUCOMIPr : I<0xE8, AddRegFrm>, DF, Imp<[ST0],[]>, // CC = compare ST(0) with ST(i), pop - II<(ops RST:$reg), "fucomip %ST(0), $reg">; +def FUCOMIPr : I<0xE8, AddRegFrm, (ops RST:$reg), + "fucomip %ST(0), $reg">, DF, Imp<[ST0],[]>; // CC = compare ST(0) with ST(i), pop // Floating point flag ops -def FNSTSW8r : I<0xE0, RawFrm>, DF, Imp<[],[AX]>, // AX = fp flags - II<(ops), "fnstsw">; +def FNSTSW8r : I<0xE0, RawFrm, (ops), "fnstsw">, 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] From brukman at cs.uiuc.edu Tue Aug 10 15:28:23 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 15:28:23 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9RegisterInfo.td Message-ID: <200408102028.PAA18732@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9RegisterInfo.td updated: 1.1 -> 1.2 --- Log message: Fix file header comment: update filename, set tablegen emacs mode. --- Diffs of the changes: (+1 -1) Index: llvm/lib/Target/SparcV9/SparcV9RegisterInfo.td diff -u llvm/lib/Target/SparcV9/SparcV9RegisterInfo.td:1.1 llvm/lib/Target/SparcV9/SparcV9RegisterInfo.td:1.2 --- llvm/lib/Target/SparcV9/SparcV9RegisterInfo.td:1.1 Tue Aug 10 13:14:04 2004 +++ llvm/lib/Target/SparcV9/SparcV9RegisterInfo.td Tue Aug 10 15:28:13 2004 @@ -1,4 +1,4 @@ -//===- SparcV9_Reg.td - SparcV9 Register definitions ----------------------===// +//===- SparcV9RegisterInfo.td - SparcV9 Register defs ------*- tablegen -*-===// // // The LLVM Compiler Infrastructure // From natebegeman at mac.com Tue Aug 10 15:42:47 2004 From: natebegeman at mac.com (Nate Begeman) Date: Tue, 10 Aug 2004 15:42:47 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCISelSimple.cpp PowerPCInstrInfo.td README.txt Message-ID: <200408102042.PAA19007@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCISelSimple.cpp updated: 1.54 -> 1.55 PowerPCInstrInfo.td updated: 1.15 -> 1.16 README.txt updated: 1.11 -> 1.12 --- Log message: Fix casts of float to unsigned long Replace STDX (store 64 bit int indexed) with STFDX (store double indexed) Fix latent bug in indexed load generation Generate indexed loads and stores in many more cases --- Diffs of the changes: (+92 -41) Index: llvm/lib/Target/PowerPC/PowerPCISelSimple.cpp diff -u llvm/lib/Target/PowerPC/PowerPCISelSimple.cpp:1.54 llvm/lib/Target/PowerPC/PowerPCISelSimple.cpp:1.55 --- llvm/lib/Target/PowerPC/PowerPCISelSimple.cpp:1.54 Fri Aug 6 01:58:50 2004 +++ llvm/lib/Target/PowerPC/PowerPCISelSimple.cpp Tue Aug 10 15:42:36 2004 @@ -82,9 +82,9 @@ std::map RegMap; // Mapping between Values and SSA Regs // External functions used in the Module - Function *fmodfFn, *fmodFn, *__moddi3Fn, *__divdi3Fn, *__umoddi3Fn, - *__udivdi3Fn, *__fixsfdiFn, *__fixdfdiFn, *__floatdisfFn, *__floatdidfFn, - *mallocFn, *freeFn; + Function *fmodfFn, *fmodFn, *__cmpdi2Fn, *__moddi3Fn, *__divdi3Fn, + *__umoddi3Fn, *__udivdi3Fn, *__fixsfdiFn, *__fixdfdiFn, *__fixunssfdiFn, + *__fixunsdfdiFn, *__floatdisfFn, *__floatdidfFn, *mallocFn, *freeFn; // MBBMap - Mapping between LLVM BB -> Machine BB std::map MBBMap; @@ -103,6 +103,7 @@ bool doInitialization(Module &M) { // Add external functions that we may call + Type *i = Type::IntTy; Type *d = Type::DoubleTy; Type *f = Type::FloatTy; Type *l = Type::LongTy; @@ -112,6 +113,8 @@ fmodfFn = M.getOrInsertFunction("fmodf", f, f, f, 0); // double fmod(double, double); fmodFn = M.getOrInsertFunction("fmod", d, d, d, 0); + // int __cmpdi2(long, long); + __cmpdi2Fn = M.getOrInsertFunction("__cmpdi2", i, l, l, 0); // long __moddi3(long, long); __moddi3Fn = M.getOrInsertFunction("__moddi3", l, l, l, 0); // long __divdi3(long, long); @@ -121,9 +124,13 @@ // unsigned long __udivdi3(unsigned long, unsigned long); __udivdi3Fn = M.getOrInsertFunction("__udivdi3", ul, ul, ul, 0); // long __fixsfdi(float) - __fixdfdiFn = M.getOrInsertFunction("__fixsfdi", l, f, 0); + __fixsfdiFn = M.getOrInsertFunction("__fixsfdi", l, f, 0); // long __fixdfdi(double) __fixdfdiFn = M.getOrInsertFunction("__fixdfdi", l, d, 0); + // unsigned long __fixunssfdi(float) + __fixunssfdiFn = M.getOrInsertFunction("__fixunssfdi", ul, f, 0); + // unsigned long __fixunsdfdi(double) + __fixunsdfdiFn = M.getOrInsertFunction("__fixunsdfdi", ul, d, 0); // float __floatdisf(long) __floatdisfFn = M.getOrInsertFunction("__floatdisf", f, l, 0); // double __floatdidf(long) @@ -283,7 +290,8 @@ void emitGEPOperation(MachineBasicBlock *BB, MachineBasicBlock::iterator IP, Value *Src, User::op_iterator IdxBegin, User::op_iterator IdxEnd, unsigned TargetReg, - bool CollapseRemainder, ConstantSInt **Remainder); + bool CollapseRemainder, ConstantSInt **Remainder, + unsigned *PendingAddReg); /// emitCastOperation - Common code shared between visitCastInst and /// constant expression cast support. @@ -375,18 +383,18 @@ unsigned makeAnotherReg(const Type *Ty) { assert(dynamic_cast(TM.getRegisterInfo()) && "Current target doesn't have PPC reg info??"); - const PowerPCRegisterInfo *MRI = + const PowerPCRegisterInfo *PPCRI = static_cast(TM.getRegisterInfo()); if (Ty == Type::LongTy || Ty == Type::ULongTy) { - const TargetRegisterClass *RC = MRI->getRegClassForType(Type::IntTy); - // Create the lower part + const TargetRegisterClass *RC = PPCRI->getRegClassForType(Type::IntTy); + // Create the upper part F->getSSARegMap()->createVirtualRegister(RC); - // Create the upper part. + // Create the lower part. return F->getSSARegMap()->createVirtualRegister(RC)-1; } // Add the mapping of regnumber => reg class to MachineFunction - const TargetRegisterClass *RC = MRI->getRegClassForType(Ty); + const TargetRegisterClass *RC = PPCRI->getRegClassForType(Ty); return F->getSSARegMap()->createVirtualRegister(RC); } @@ -2478,12 +2486,14 @@ // otherwise, we copy the offset into another reg, and use reg+reg addressing. if (GetElementPtrInst *GEPI = canFoldGEPIntoLoadOrStore(SourceAddr)) { unsigned baseReg = getReg(GEPI); + unsigned pendingAdd; ConstantSInt *offset; emitGEPOperation(BB, BB->end(), GEPI->getOperand(0), GEPI->op_begin()+1, - GEPI->op_end(), baseReg, true, &offset); + GEPI->op_end(), baseReg, true, &offset, &pendingAdd); - if (Class != cLong && canUseAsImmediateForOpcode(offset, 0)) { + if (pendingAdd == 0 && Class != cLong && + canUseAsImmediateForOpcode(offset, 0)) { if (Class == cByte && I.getType()->isSigned()) { unsigned TmpReg = makeAnotherReg(I.getType()); BuildMI(BB, ImmOpcode, 2, TmpReg).addSImm(offset->getValue()) @@ -2496,7 +2506,7 @@ return; } - unsigned indexReg = getReg(offset); + unsigned indexReg = (pendingAdd != 0) ? pendingAdd : getReg(offset); if (Class == cLong) { unsigned indexPlus4 = makeAnotherReg(Type::IntTy); @@ -2505,7 +2515,7 @@ BuildMI(BB, IdxOpcode, 2, DestReg+1).addReg(indexPlus4).addReg(baseReg); } else if (Class == cByte && I.getType()->isSigned()) { unsigned TmpReg = makeAnotherReg(I.getType()); - BuildMI(BB, IdxOpcode, 2, DestReg).addReg(indexReg).addReg(baseReg); + BuildMI(BB, IdxOpcode, 2, TmpReg).addReg(indexReg).addReg(baseReg); BuildMI(BB, PPC32::EXTSB, 1, DestReg).addReg(TmpReg); } else { BuildMI(BB, IdxOpcode, 2, DestReg).addReg(indexReg).addReg(baseReg); @@ -2540,7 +2550,7 @@ // Indexed opcodes, for reg+reg addressing static const unsigned IdxOpcodes[] = { PPC32::STBX, PPC32::STHX, PPC32::STWX, - PPC32::STFSX, PPC32::STDX, PPC32::STWX + PPC32::STFSX, PPC32::STFDX, PPC32::STWX }; Value *SourceAddr = I.getOperand(1); @@ -2558,18 +2568,20 @@ // otherwise, we copy the offset into another reg, and use reg+reg addressing. if (GetElementPtrInst *GEPI = canFoldGEPIntoLoadOrStore(SourceAddr)) { unsigned baseReg = getReg(GEPI); + unsigned pendingAdd; ConstantSInt *offset; emitGEPOperation(BB, BB->end(), GEPI->getOperand(0), GEPI->op_begin()+1, - GEPI->op_end(), baseReg, true, &offset); + GEPI->op_end(), baseReg, true, &offset, &pendingAdd); - if (Class != cLong && canUseAsImmediateForOpcode(offset, 0)) { + if (0 == pendingAdd && Class != cLong && + canUseAsImmediateForOpcode(offset, 0)) { BuildMI(BB, ImmOpcode, 3).addReg(ValReg).addSImm(offset->getValue()) .addReg(baseReg); return; } - unsigned indexReg = getReg(offset); + unsigned indexReg = (pendingAdd != 0) ? pendingAdd : getReg(offset); if (Class == cLong) { unsigned indexPlus4 = makeAnotherReg(Type::IntTy); @@ -2749,11 +2761,15 @@ // Handle casts from floating point to integer now... if (SrcClass == cFP32 || SrcClass == cFP64) { + static Function* const Funcs[] = + { __fixsfdiFn, __fixdfdiFn, __fixunssfdiFn, __fixunsdfdiFn }; // emit library call if (DestClass == cLong) { + bool isDouble = SrcClass == cFP64; + unsigned nameIndex = 2 * DestTy->isSigned() + isDouble; std::vector Args; Args.push_back(ValueRecord(SrcReg, SrcTy)); - Function *floatFn = (DestClass == cFP32) ? __fixsfdiFn : __fixdfdiFn; + Function *floatFn = Funcs[nameIndex]; MachineInstr *TheCall = BuildMI(PPC32::CALLpcrel, 1).addGlobalAddress(floatFn, true); doCall(ValueRecord(DestReg, DestTy), TheCall, Args, false); @@ -3120,7 +3136,7 @@ unsigned outputReg = getReg(I); emitGEPOperation(BB, BB->end(), I.getOperand(0), I.op_begin()+1, I.op_end(), - outputReg, false, 0); + outputReg, false, 0, 0); } /// emitGEPOperation - Common code shared between visitGetElementPtrInst and @@ -3130,7 +3146,8 @@ MachineBasicBlock::iterator IP, Value *Src, User::op_iterator IdxBegin, User::op_iterator IdxEnd, unsigned TargetReg, - bool GEPIsFolded, ConstantSInt **RemainderPtr) { + bool GEPIsFolded, ConstantSInt **RemainderPtr, + unsigned *PendingAddReg) { const TargetData &TD = TM.getTargetData(); const Type *Ty = Src->getType(); unsigned basePtrReg = getReg(Src, MBB, IP); @@ -3199,18 +3216,32 @@ } } // Emit instructions for all the collapsed ops + bool pendingAdd = false; + unsigned pendingAddReg = 0; + for(std::vector::iterator cgo_i = ops.begin(), cgo_e = ops.end(); cgo_i != cgo_e; ++cgo_i) { CollapsedGepOp& cgo = *cgo_i; - unsigned nextBasePtrReg = makeAnotherReg (Type::IntTy); + unsigned nextBasePtrReg = makeAnotherReg(Type::IntTy); + + // If we didn't emit an add last time through the loop, we need to now so + // that the base reg is updated appropriately. + if (pendingAdd) { + assert(pendingAddReg != 0 && "Uninitialized register in pending add!"); + BuildMI(*MBB, IP, PPC32::ADD, 2, nextBasePtrReg).addReg(basePtrReg) + .addReg(pendingAddReg); + basePtrReg = nextBasePtrReg; + nextBasePtrReg = makeAnotherReg(Type::IntTy); + pendingAddReg = 0; + pendingAdd = false; + } if (cgo.isMul) { // We know the elementSize is a constant, so we can emit a constant mul - // and then add it to the current base reg unsigned TmpReg = makeAnotherReg(Type::IntTy); - doMultiplyConst(MBB, IP, TmpReg, cgo.index, cgo.size); - BuildMI(*MBB, IP, PPC32::ADD, 2, nextBasePtrReg).addReg(basePtrReg) - .addReg(TmpReg); + doMultiplyConst(MBB, IP, nextBasePtrReg, cgo.index, cgo.size); + pendingAddReg = basePtrReg; + pendingAdd = true; } else { // Try and generate an immediate addition if possible if (cgo.size->isNullValue()) { @@ -3235,16 +3266,41 @@ // the target, and save the current constant offset so the folding load or // store can try and use it as an immediate. if (GEPIsFolded) { - BuildMI (BB, PPC32::OR, 2, TargetReg).addReg(basePtrReg).addReg(basePtrReg); + // If this is a folded GEP and the last element was an index, then we need + // to do some extra work to turn a shift/add/stw into a shift/stwx + if (pendingAdd && 0 == remainder->getValue()) { + assert(pendingAddReg != 0 && "Uninitialized register in pending add!"); + *PendingAddReg = pendingAddReg; + } else { + *PendingAddReg = 0; + if (pendingAdd) { + unsigned nextBasePtrReg = makeAnotherReg(Type::IntTy); + assert(pendingAddReg != 0 && "Uninitialized register in pending add!"); + BuildMI(*MBB, IP, PPC32::ADD, 2, nextBasePtrReg).addReg(basePtrReg) + .addReg(pendingAddReg); + basePtrReg = nextBasePtrReg; + } + } + BuildMI (*MBB, IP, PPC32::OR, 2, TargetReg).addReg(basePtrReg) + .addReg(basePtrReg); *RemainderPtr = remainder; return; } + + // If we still have a pending add at this point, emit it now + if (pendingAdd) { + unsigned TmpReg = makeAnotherReg(Type::IntTy); + BuildMI(*MBB, IP, PPC32::ADD, 2, TmpReg).addReg(pendingAddReg) + .addReg(basePtrReg); + basePtrReg = TmpReg; + } // After we have processed all the indices, the result is left in // basePtrReg. Move it to the register where we were expected to // put the answer. if (remainder->isNullValue()) { - BuildMI (BB, PPC32::OR, 2, TargetReg).addReg(basePtrReg).addReg(basePtrReg); + BuildMI (*MBB, IP, PPC32::OR, 2, TargetReg).addReg(basePtrReg) + .addReg(basePtrReg); } else if (canUseAsImmediateForOpcode(remainder, 0)) { BuildMI(*MBB, IP, PPC32::ADDI, 2, TargetReg).addReg(basePtrReg) .addSImm(remainder->getValue()); Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.15 llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.16 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.15 Mon Aug 9 12:24:04 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.td Tue Aug 10 15:42:36 2004 @@ -143,10 +143,10 @@ def STWU : DForm_3<"stwu", 37, 0, 0>; def STWX : XForm_8<"stwx", 31, 151, 0, 0>; def STWUX : XForm_8<"stwux", 31, 183, 0, 0>; -def STDX : XForm_8<"stdx", 31, 149, 1, 0>; def STFS : DForm_9<"stfs", 52, 0, 0>; -def STFSX : XForm_28<"stfsx", 31, 302, 0, 0>; +def STFSX : XForm_28<"stfsx", 31, 663, 0, 0>; def STFD : DForm_9<"stfd", 54, 0, 0>; +def STFDX : XForm_28<"stfdx", 31, 727, 0, 0>; def SUBFIC : DForm_2<"subfic", 8, 0, 0>; def SUB : XOForm_1_rev<"sub", 31, 40, 0, 0, 0, 0>; def SUBF : XOForm_1<"subf", 31, 40, 0, 0, 0, 0>; Index: llvm/lib/Target/PowerPC/README.txt diff -u llvm/lib/Target/PowerPC/README.txt:1.11 llvm/lib/Target/PowerPC/README.txt:1.12 --- llvm/lib/Target/PowerPC/README.txt:1.11 Fri Aug 6 01:58:50 2004 +++ llvm/lib/Target/PowerPC/README.txt Tue Aug 10 15:42:36 2004 @@ -1,9 +1,7 @@ -Currently unimplemented: -* cast fp to bool -* signed right shift of long by reg - -Current bugs: -* ulong to double. ahhh, here's the problem: +TODO: +* implement cast fp to bool +* implement signed right shift by reg +* fix ulong to double: floatdidf assumes signed longs. so if the high but of a ulong just happens to be set, you get the wrong sign. The fix for this is to call cmpdi2 to compare against zero, if so shift right by one, @@ -19,10 +17,7 @@ shift right ulong a, 1 (we could use emitShift) call floatdidf fadd f1, f1, f1 (fp left shift by 1) -* linking llvmg++ .s files with gcc instead of g++ - -Codegen improvements needed: -* PowerPCPEI.cpp needs to save/restore regs in the opposite order +* PowerPCPEI.cpp needs to be replaced by shiny new target hook * setCondInst needs to know branchless versions of seteq/setne/etc * cast elimination pass (uint -> sbyte -> short, kill the byte -> short) * should hint to the branch select pass that it doesn't need to print the @@ -33,7 +28,7 @@ Current hacks: * lazy insert of GlobalBaseReg definition at front of first MBB - A prime candidate for sabre's "slightly above ISel" passes. + A prime candidate for sabre's future "slightly above ISel" passes. * cast code is huge, unwieldy. Should probably be broken up into smaller pieces. * visitLoadInst is getting awfully cluttered as well. From brukman at cs.uiuc.edu Tue Aug 10 15:55:08 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 15:55:08 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/CodeEmitterGen.cpp Message-ID: <200408102055.PAA19257@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: CodeEmitterGen.cpp updated: 1.35 -> 1.36 --- Log message: Deleted commented-out code as we now get namespace directly, add comments --- Diffs of the changes: (+3 -2) Index: llvm/utils/TableGen/CodeEmitterGen.cpp diff -u llvm/utils/TableGen/CodeEmitterGen.cpp:1.35 llvm/utils/TableGen/CodeEmitterGen.cpp:1.36 --- llvm/utils/TableGen/CodeEmitterGen.cpp:1.35 Tue Aug 10 13:31:01 2004 +++ llvm/utils/TableGen/CodeEmitterGen.cpp Tue Aug 10 15:54:58 2004 @@ -24,15 +24,16 @@ std::vector Insts = Records.getAllDerivedDefinitions("Instruction"); EmitSourceFileHeader("Machine Code Emitter", o); - std::string Namespace = Insts[0]->getValueAsString("Namespace") + "::"; - //const std::string &Namespace = Inst->getValue("Namespace")->getName(); + // Emit function declaration o << "unsigned " << Target.getName() << "CodeEmitter::" << "getBinaryCodeForInstr(MachineInstr &MI) {\n" << " unsigned Value = 0;\n" << " DEBUG(std::cerr << MI);\n" << " switch (MI.getOpcode()) {\n"; + + // Emit a case statement for each opcode for (std::vector::iterator I = Insts.begin(), E = Insts.end(); I != E; ++I) { Record *R = *I; From lattner at cs.uiuc.edu Tue Aug 10 16:02:25 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 16:02:25 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200408102102.QAA19962@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.91 -> 1.92 --- Log message: Drop the first argument of FPI, and asmprinterify fxch --- Diffs of the changes: (+32 -28) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.91 llvm/lib/Target/X86/X86InstrInfo.td:1.92 --- llvm/lib/Target/X86/X86InstrInfo.td:1.91 Tue Aug 10 15:17:41 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Tue Aug 10 16:02:13 2004 @@ -764,7 +764,7 @@ 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 FPI o, Format F, FPFormat fp> : FPInst<"", o, F, fp, NoMem, NoImm>; class FPIM o, Format F, FPFormat fp, MemType m> : FPInst; @@ -777,14 +777,14 @@ // 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<"", 0, Pseudo, SpecialFP>; // f1 = fmov f2 -def FpADD : FPI<"", 0, Pseudo, TwoArgFP>; // f1 = fadd f2, f3 -def FpSUB : FPI<"", 0, Pseudo, TwoArgFP>; // f1 = fsub f2, f3 -def FpMUL : FPI<"", 0, Pseudo, TwoArgFP>; // f1 = fmul f2, f3 -def FpDIV : FPI<"", 0, Pseudo, TwoArgFP>; // f1 = fdiv f2, f3 +def FpMOV : FPI<0, Pseudo, SpecialFP>; // f1 = fmov f2 +def FpADD : FPI<0, Pseudo, TwoArgFP>; // f1 = fadd f2, f3 +def FpSUB : FPI<0, Pseudo, TwoArgFP>; // f1 = fsub f2, f3 +def FpMUL : FPI<0, Pseudo, TwoArgFP>; // f1 = fmul f2, f3 +def FpDIV : FPI<0, Pseudo, TwoArgFP>; // f1 = fdiv f2, f3 -def FpGETRESULT : FPI<"",0, Pseudo, SpecialFP>; // FPR = ST(0) -def FpSETRESULT : FPI<"",0, Pseudo, SpecialFP>; // ST(0) = FPR +def FpGETRESULT : FPI<0, Pseudo, SpecialFP>; // FPR = ST(0) +def FpSETRESULT : FPI<0, Pseudo, SpecialFP>; // ST(0) = FPR // FADD reg, mem: Before stackification, these are represented by: R1 = FADD* R2, [mem] def FADD32m : FPI32m<"fadd", 0xD8, MRM0m, OneArgFPRW>; // ST(0) = ST(0) + [mem32real] @@ -827,22 +827,23 @@ // Floating point cmovs... let isTwoAddress = 1, Uses = [ST0], Defs = [ST0] in { - def FCMOVB : FPI<"" , 0xC0, AddRegFrm, CondMovFP>, DA, // fcmovb ST(i) -> ST(0) + def FCMOVB : FPI<0xC0, AddRegFrm, CondMovFP>, DA, // fcmovb ST(i) -> ST(0) II<(ops RST:$op), "fcmovb %ST(0), $op">; - def FCMOVBE : FPI<"", 0xD0, AddRegFrm, CondMovFP>, DA, // fcmovbe ST(i) -> ST(0) + def FCMOVBE : FPI<0xD0, AddRegFrm, CondMovFP>, DA, // fcmovbe ST(i) -> ST(0) II<(ops RST:$op), "fcmovbe %ST(0), $op">; - def FCMOVE : FPI<"" , 0xC8, AddRegFrm, CondMovFP>, DA, // fcmove ST(i) -> ST(0) + def FCMOVE : FPI<0xC8, AddRegFrm, CondMovFP>, DA, // fcmove ST(i) -> ST(0) II<(ops RST:$op), "fcmove %ST(0), $op">; - def FCMOVAE : FPI<"", 0xC0, AddRegFrm, CondMovFP>, DB, // fcmovae ST(i) -> ST(0) + def FCMOVAE : FPI<0xC0, AddRegFrm, CondMovFP>, DB, // fcmovae ST(i) -> ST(0) II<(ops RST:$op), "fcmovae %ST(0), $op">; - def FCMOVA : FPI<"" , 0xD0, AddRegFrm, CondMovFP>, DB, // fcmova ST(i) -> ST(0) + def FCMOVA : FPI<0xD0, AddRegFrm, CondMovFP>, DB, // fcmova ST(i) -> ST(0) II<(ops RST:$op), "fcmova %ST(0), $op">; - def FCMOVNE : FPI<"", 0xC8, AddRegFrm, CondMovFP>, DB, // fcmovne ST(i) -> ST(0) + def FCMOVNE : FPI<0xC8, AddRegFrm, CondMovFP>, DB, // fcmovne ST(i) -> ST(0) II<(ops RST:$op), "fcmovne %ST(0), $op">; } // Floating point loads & stores... -def FLDrr : FPI <"fld" , 0xC0, AddRegFrm, NotFP>, D9; // push(ST(i)) +let Name = "fld" in +def FLDrr : FPI<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 @@ -850,8 +851,10 @@ 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 +let Name = "fst" in + def FSTrr : FPI<0xD0, AddRegFrm, NotFP >, DD; // ST(i) = ST(0) +let Name = "fstp" in + def FSTPrr : FPI<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 @@ -864,20 +867,21 @@ def FISTP32m : FPI32m <"fistp", 0xDB, MRM3m , NotFP >; // store signed int, pop def FISTP64m : FPI64m <"fistpll", 0xDF, MRM7m , OneArgFP>; // store signed long, pop -def FXCH : FPI <"fxch", 0xC8, AddRegFrm, NotFP>, D9; // fxch ST(i), ST(0) +def FXCH : FPI<0xC8, AddRegFrm, NotFP>, + II<(ops RST:$op), "fxch $op">, D9; // fxch ST(i), ST(0) // Floating point constant loads... -def FLD0 : FPI<"", 0xEE, RawFrm, ZeroArgFP>, D9, +def FLD0 : FPI<0xEE, RawFrm, ZeroArgFP>, D9, II<(ops), "fldz">; -def FLD1 : FPI<"", 0xE8, RawFrm, ZeroArgFP>, D9, +def FLD1 : FPI<0xE8, RawFrm, ZeroArgFP>, D9, II<(ops), "fld1">; // Unary operations... -def FCHS : FPI<"", 0xE0, RawFrm, OneArgFPRW>, D9, // f1 = fchs f2 - II<(ops), "fchs">; -def FTST : FPI<"", 0xE4, RawFrm, OneArgFP>, D9, // ftst ST(0) - II<(ops), "ftst">; +def FCHS : FPI<0xE0, RawFrm, OneArgFPRW>, // f1 = fchs f2 + II<(ops), "fchs">, D9; +def FTST : FPI<0xE4, RawFrm, OneArgFP>, // ftst ST(0) + II<(ops), "ftst">, D9; // Binary arithmetic operations... class FPST0rInst o, dag ops, string asm> : I, D8 { @@ -916,15 +920,15 @@ def FDIVRPrST0 : FPrST0PInst<0xF0, (ops RST:$op), "fdivrp $op">; // ST(i) = ST(0) / ST(i), pop // Floating point compares -def FUCOMr : FPI<"", 0xE0, AddRegFrm, CompareFP>, DD, Imp<[ST0],[]>, // FPSW = compare ST(0) with ST(i) - II<(ops RST:$reg), "fucom $reg">; +def FUCOMr : FPI<0xE0, AddRegFrm, CompareFP>, // FPSW = compare ST(0) with ST(i) + II<(ops RST:$reg), "fucom $reg">, DD, Imp<[ST0],[]>; def FUCOMPr : I<0xE8, AddRegFrm, (ops RST:$reg), "fucomp $reg">, DD, Imp<[ST0],[]>; // FPSW = compare ST(0) with ST(i), pop def FUCOMPPr : I<0xE9, RawFrm, (ops), "fucompp">, DA, Imp<[ST0],[]>; // compare ST(0) with ST(1), pop, pop -def FUCOMIr : FPI<"", 0xE8, AddRegFrm, CompareFP>, DB, Imp<[ST0],[]>, // CC = compare ST(0) with ST(i) - II<(ops RST:$reg), "fucomi %ST(0), $reg">; +def FUCOMIr : FPI<0xE8, AddRegFrm, CompareFP>, // CC = compare ST(0) with ST(i) + II<(ops RST:$reg), "fucomi %ST(0), $reg">, DB, Imp<[ST0],[]>; def FUCOMIPr : I<0xE8, AddRegFrm, (ops RST:$reg), "fucomip %ST(0), $reg">, DF, Imp<[ST0],[]>; // CC = compare ST(0) with ST(i), pop From lattner at cs.uiuc.edu Tue Aug 10 16:21:43 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 16:21:43 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200408102121.QAA20009@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.92 -> 1.93 --- Log message: This is purely a formatting patch that gets us closer to the mecca of fitting X86InstrInfo.td into 80 columns --- Diffs of the changes: (+104 -61) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.92 llvm/lib/Target/X86/X86InstrInfo.td:1.93 --- llvm/lib/Target/X86/X86InstrInfo.td:1.92 Tue Aug 10 16:02:13 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Tue Aug 10 16:21:30 2004 @@ -470,22 +470,30 @@ def AND16rm : Im16 <"and", 0x23, MRMSrcMem >, OpSize; // R16 &= [mem16] def AND32rm : Im32 <"and", 0x23, MRMSrcMem >; // R32 &= [mem32] -def AND8ri : Ii8 <0x80, MRM4r, (ops R8:$dst, R8:$src1, i8imm:$src2), "and $dst, $src2">; -def AND16ri : Ii16 <0x81, MRM4r, (ops R16:$dst, R16:$src1, i16imm:$src2), "and $dst, $src2">, OpSize; -def AND32ri : Ii32 <0x81, MRM4r, (ops R32:$dst, R32:$src1, i32imm:$src2), "and $dst, $src2">; +def AND8ri : Ii8 <0x80, MRM4r, (ops R8 :$dst, R8 :$src1, i8imm :$src2), + "and $dst, $src2">; +def AND16ri : Ii16<0x81, MRM4r, (ops R16:$dst, R16:$src1, i16imm:$src2), + "and $dst, $src2">, OpSize; +def AND32ri : Ii32<0x81, MRM4r, (ops R32:$dst, R32:$src1, i32imm:$src2), + "and $dst, $src2">; 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 <0x83, MRM4r, (ops R16:$dst, R16:$src1, i8imm:$src2), "and $dst, $src2" >, OpSize; // R16 &= imm8 -def AND32ri8 : Ii8 <0x83, MRM4r, (ops R32:$dst, R32:$src1, i8imm:$src2), "and $dst, $src2">; // R32 &= imm8 +def AND16ri8 : Ii8<0x83, MRM4r, (ops R16:$dst, R16:$src1, i8imm:$src2), + "and $dst, $src2" >, OpSize; +def AND32ri8 : Ii8<0x83, MRM4r, (ops R32:$dst, R32:$src1, i8imm:$src2), + "and $dst, $src2">; def AND16mi8 : Im16i8<"and", 0x83, MRM4m >, OpSize; // [mem16] &= imm8 def AND32mi8 : Im32i8<"and", 0x83, MRM4m >; // [mem32] &= imm8 -def OR8rr : I<0x08, MRMDestReg, (ops R8:$dst, R8:$src1, R8:$src2), "or $dst, $src2">; -def OR16rr : I<0x09, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "or $dst, $src2">, OpSize; -def OR32rr : I<0x09, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "or $dst, $src2">; +def OR8rr : I<0x08, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), + "or $dst, $src2">; +def OR16rr : I<0x09, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), + "or $dst, $src2">, OpSize; +def OR32rr : I<0x09, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), + "or $dst, $src2">; 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 @@ -493,17 +501,22 @@ def OR16rm : Im16 <"or" , 0x0B, MRMSrcMem >, OpSize; // R16 |= [mem16] def OR32rm : Im32 <"or" , 0x0B, MRMSrcMem >; // R32 |= [mem32] -def OR8ri : Ii8 <0x80, MRM1r, (ops R8:$dst, R8:$src1, i8imm:$src2), "or $dst, $src2">; -def OR16ri : Ii16 <0x81, MRM1r, (ops R16:$dst, R16:$src1, i16imm:$src2), "or $dst, $src2">, OpSize; -def OR32ri : Ii32 <0x81, MRM1r, (ops R32:$dst, R32:$src1, i32imm:$src2), "or $dst, $src2">; -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 <0x83, MRM1r, (ops R8:$dst, R8:$src1, i8imm:$src2), "or $dst, $src2">, OpSize; // R16 |= imm8 -def OR32ri8 : Ii8 <0x83, MRM1r, (ops R32:$dst, R32:$src1, i8imm:$src2), "or $dst, $src2">; // R32 |= imm8 -def OR16mi8 : Im16i8<"or" , 0x83, MRM1m >, OpSize; // [mem16] |= imm8 -def OR32mi8 : Im32i8<"or" , 0x83, MRM1m >; // [mem32] |= imm8 +def OR8ri : Ii8 <0x80, MRM1r, (ops R8 :$dst, R8 :$src1, i8imm:$src2), + "or $dst, $src2">; +def OR16ri : Ii16<0x81, MRM1r, (ops R16:$dst, R16:$src1, i16imm:$src2), + "or $dst, $src2">, OpSize; +def OR32ri : Ii32<0x81, MRM1r, (ops R32:$dst, R32:$src1, i32imm:$src2), + "or $dst, $src2">; +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<0x83, MRM1r, (ops R8 :$dst, R8 :$src1, i8imm:$src2), + "or $dst, $src2">, OpSize; +def OR32ri8 : Ii8<0x83, MRM1r, (ops R32:$dst, R32:$src1, i8imm:$src2), + "or $dst, $src2">; +def OR16mi8 : Im16i8<"or" , 0x83, MRM1m>, OpSize; // [mem16] |= imm8 +def OR32mi8 : Im32i8<"or" , 0x83, MRM1m>; // [mem32] |= imm8 def XOR8rr : I<0x30, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "xor $dst, $src2">; @@ -523,8 +536,10 @@ def XOR16mi : Im16i16<"xor", 0x81, MRM6m >, OpSize; // [mem16] ^= R16 def XOR32mi : Im32i32<"xor", 0x81, MRM6m >; // [mem32] ^= R32 -def XOR16ri8 : Ii8 <0x83, MRM6r, (ops R16:$dst, R16:$src1, i8imm:$src2), "xor $dst, $src2">, OpSize; // R16 ^= imm8 -def XOR32ri8 : Ii8 <0x83, MRM6r, (ops R32:$dst, R32:$src1, i8imm:$src2), "xor $dst, $src2">; // R32 ^= imm8 +def XOR16ri8 : Ii8<0x83, MRM6r, (ops R16:$dst, R16:$src1, i8imm:$src2), + "xor $dst, $src2">, OpSize; +def XOR32ri8 : Ii8<0x83, MRM6r, (ops R32:$dst, R32:$src1, i8imm:$src2), + "xor $dst, $src2">; def XOR16mi8 : Im16i8<"xor", 0x83, MRM6m >, OpSize; // [mem16] ^= imm8 def XOR32mi8 : Im32i8<"xor", 0x83, MRM6m >; // [mem32] ^= imm8 @@ -539,9 +554,12 @@ def SHL32mCL : Im32 <"shl", 0xD3, MRM4m > ; // [mem32] <<= cl } -def SHL8ri : Ii8 <0xC0, MRM4r, (ops R8:$dst, R8:$src1, i8imm:$src2), "shl $dst, $src2">; // R8 <<= imm8 -def SHL16ri : Ii8 <0xC1, MRM4r, (ops R16:$dst, R16:$src1, i8imm:$src2), "shl $dst, $src2">, OpSize; // R16 <<= imm8 -def SHL32ri : Ii8 <0xC1, MRM4r, (ops R32:$dst, R32:$src1, i8imm:$src2), "shl $dst, $src2">; // R32 <<= imm8 +def SHL8ri : Ii8<0xC0, MRM4r, (ops R8 :$dst, R8 :$src1, i8imm:$src2), + "shl $dst, $src2">; +def SHL16ri : Ii8<0xC1, MRM4r, (ops R16:$dst, R16:$src1, i8imm:$src2), + "shl $dst, $src2">, OpSize; +def SHL32ri : Ii8<0xC1, MRM4r, (ops R32:$dst, R32:$src1, i8imm:$src2), + "shl $dst, $src2">; 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 @@ -555,9 +573,9 @@ def SHR32mCL : Im32 <"shr", 0xD3, MRM5m > ; // [mem32] >>= cl } -def SHR8ri : Ii8 <0xC0, MRM5r, (ops R8:$dst, R8:$src1, i8imm:$src2), "shr $dst, $src2">; // R8 >>= imm8 -def SHR16ri : Ii8 <0xC1, MRM5r, (ops R16:$dst, R16:$src1, i8imm:$src2), "shr $dst, $src2">, OpSize; // R16 >>= imm8 -def SHR32ri : Ii8 <0xC1, MRM5r, (ops R32:$dst, R32:$src1, i8imm:$src2), "shr $dst, $src2">; // R32 >>= imm8 +def SHR8ri : Ii8 <0xC0, MRM5r, (ops R8:$dst, R8:$src1, i8imm:$src2), "shr $dst, $src2">; +def SHR16ri : Ii8 <0xC1, MRM5r, (ops R16:$dst, R16:$src1, i8imm:$src2), "shr $dst, $src2">, OpSize; +def SHR32ri : Ii8 <0xC1, MRM5r, (ops R32:$dst, R32:$src1, i8imm:$src2), "shr $dst, $src2">; 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 @@ -571,23 +589,30 @@ def SAR32mCL : Im32 <"sar", 0xD3, MRM7m > ; // [mem32] >>>= cl } -def SAR8ri : Ii8 <0xC0, MRM7r, (ops R8:$dst, R8:$src1, i8imm:$src2), "sar $dst, $src2">; // R8 >>>= imm8 -def SAR16ri : Ii8 <0xC1, MRM7r, (ops R16:$dst, R16:$src1, i8imm:$src2), "sar $dst, $src2">, OpSize; // R16 >>>= imm8 -def SAR32ri : Ii8 <0xC1, MRM7r, (ops R32:$dst, R32:$src1, i8imm:$src2), "sar $dst, $src2">; // R32 >>>= imm8 +def SAR8ri : Ii8<0xC0, MRM7r, (ops R8 :$dst, R8 :$src1, i8imm:$src2), + "sar $dst, $src2">; +def SAR16ri : Ii8<0xC1, MRM7r, (ops R16:$dst, R16:$src1, i8imm:$src2), + "sar $dst, $src2">, OpSize; +def SAR32ri : Ii8<0xC1, MRM7r, (ops R32:$dst, R32:$src1, i8imm:$src2), + "sar $dst, $src2">; 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 let Uses = [CL], printImplicitUsesAfter = 1 in { - def SHLD32rrCL : I<0xA5, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "shld $dst, $src2, %CL">, TB; + def SHLD32rrCL : I<0xA5, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), + "shld $dst, $src2, %CL">, TB; def SHLD32mrCL : Im32 <"shld", 0xA5, MRMDestMem>, TB; // [mem32] <<= [mem32],R32 cl - def SHRD32rrCL : I<0xAD, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "shrd $dst, $src2, %CL">, TB; + def SHRD32rrCL : I<0xAD, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), + "shrd $dst, $src2, %CL">, TB; def SHRD32mrCL : Im32 <"shrd", 0xAD, MRMDestMem>, TB; // [mem32] >>= [mem32],R32 cl } -def SHLD32rri8 : Ii8 <0xA4, MRMDestReg, (ops R8:$dst, R8:$src1, i8imm:$src2), "shld $dst, $src2">, TB; // R32 <<= R32,R32 imm8 +def SHLD32rri8 : Ii8 <0xA4, MRMDestReg, (ops R8:$dst, R8:$src1, i8imm:$src2), + "shld $dst, $src2">, TB; def SHLD32mri8 : Im32i8<"shld", 0xA4, MRMDestMem>, TB; // [mem32] <<= [mem32],R32 imm8 -def SHRD32rri8 : Ii8 <0xAC, MRMDestReg, (ops R16:$dst, R16:$src1, i8imm:$src2), "shrd $dst, $src2">, TB; // R32 >>= R32,R32 imm8 +def SHRD32rri8 : Ii8 <0xAC, MRMDestReg, (ops R16:$dst, R16:$src1, i8imm:$src2), + "shrd $dst, $src2">, TB; def SHRD32mri8 : Im32i8<"shrd", 0xAC, MRMDestMem>, TB; // [mem32] >>= [mem32],R32 imm8 @@ -617,8 +642,8 @@ def ADC32rr : I<0x11, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "adc $dst, $src2">; def ADC32mr : Im32 <"adc", 0x11, MRMDestMem>; // [mem32] += R32+Carry def ADC32rm : Im32 <"adc", 0x13, MRMSrcMem >; // R32 += [mem32]+Carry -def ADC32ri : Ii32 <0x81, MRM2r, (ops R32:$dst, R32:$src1, i32imm:$src2), "adc $dst, $src2">; // R32 += I32+Carry -def ADC32ri8 : Ii8 <0x83, MRM2r, (ops R32:$dst, R32:$src1, i8imm:$src2), "adc $dst, $src2">; // R32 += I8+Carry +def ADC32ri : Ii32 <0x81, MRM2r, (ops R32:$dst, R32:$src1, i32imm:$src2), "adc $dst, $src2">; +def ADC32ri8 : Ii8 <0x83, MRM2r, (ops R32:$dst, R32:$src1, i8imm:$src2), "adc $dst, $src2">; def ADC32mi : Im32i32<"adc", 0x81, MRM2m >; // [mem32] += I32+Carry def ADC32mi8 : Im32i8 <"adc", 0x83, MRM2m >; // [mem32] += I8+Carry @@ -632,25 +657,33 @@ def SUB16rm : Im16 <"sub", 0x2B, MRMSrcMem >, OpSize; // R16 -= [mem16] def SUB32rm : Im32 <"sub", 0x2B, MRMSrcMem >; // R32 -= [mem32] -def SUB8ri : Ii8 <0x80, MRM5r, (ops R8:$dst, R8:$src1, i8imm:$src2), "sub $dst, $src2">; -def SUB16ri : Ii16 <0x81, MRM5r, (ops R16:$dst, R16:$src1, i16imm:$src2), "sub $dst, $src2">, OpSize; -def SUB32ri : Ii32 <0x81, MRM5r, (ops R32:$dst, R32:$src1, i32imm:$src2), "sub $dst, $src2">; +def SUB8ri : Ii8 <0x80, MRM5r, (ops R8:$dst, R8:$src1, i8imm:$src2), + "sub $dst, $src2">; +def SUB16ri : Ii16<0x81, MRM5r, (ops R16:$dst, R16:$src1, i16imm:$src2), + "sub $dst, $src2">, OpSize; +def SUB32ri : Ii32<0x81, MRM5r, (ops R32:$dst, R32:$src1, i32imm:$src2), + "sub $dst, $src2">; 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 <0x83, MRM5r, (ops R16:$dst, R16:$src1, i8imm:$src2), "sub $dst, $src2">, OpSize; -def SUB32ri8 : Ii8 <0x83, MRM5r, (ops R32:$dst, R32:$src1, i8imm:$src2), "sub $dst, $src2">; +def SUB16ri8 : Ii8<0x83, MRM5r, (ops R16:$dst, R16:$src1, i8imm:$src2), + "sub $dst, $src2">, OpSize; +def SUB32ri8 : Ii8<0x83, MRM5r, (ops R32:$dst, R32:$src1, i8imm:$src2), + "sub $dst, $src2">; def SUB16mi8 : Im16i8<"sub", 0x83, MRM5m >, OpSize; // [mem16] -= I8 def SUB32mi8 : Im32i8<"sub", 0x83, MRM5m >; // [mem32] -= I8 -def SBB32rr : I<0x19, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "adc $dst, $src2">; -def SBB32mr : Im32 <"sbb", 0x19, MRMDestMem>; // [mem32] -= R32+Carry -def SBB32rm : Im32 <"sbb", 0x1B, MRMSrcMem >; // R32 -= [mem32]+Carry -def SBB32ri : Ii32 <0x81, MRM3r, (ops R32:$dst, R32:$src1, i32imm:$src2), "sbb $dst, $src2">; // R32 -= I32+Carry -def SBB32ri8 : Ii8 <0x83, MRM3r, (ops R32:$dst, R32:$src1, i8imm:$src2), "sbb $dst, $src2">; // R32 -= I8+Carry -def SBB32mi : Im32i32<"sbb", 0x81, MRM3m >; // [mem32] -= I32+Carry -def SBB32mi8 : Im32i8 <"sbb", 0x83, MRM3m >; // [mem32] -= I8+Carry +def SBB32rr : I<0x19, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), + "adc $dst, $src2">; +def SBB32mr : Im32<"sbb", 0x19, MRMDestMem>; // [mem32] -= R32+Carry +def SBB32rm : Im32<"sbb", 0x1B, MRMSrcMem >; // R32 -= [mem32]+Carry +def SBB32ri : Ii32<0x81, MRM3r, (ops R32:$dst, R32:$src1, i32imm:$src2), + "sbb $dst, $src2">; +def SBB32ri8 : Ii8<0x83, MRM3r, (ops R32:$dst, R32:$src1, i8imm:$src2), + "sbb $dst, $src2">; +def SBB32mi : Im32i32<"sbb", 0x81, MRM3m>; // [mem32] -= I32+Carry +def SBB32mi8 : Im32i8 <"sbb", 0x83, MRM3m>; // [mem32] -= I8+Carry def IMUL16rr : I<0xAF, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "imul $dst, $src2">, TB, OpSize; def IMUL32rr : I<0xAF, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "imul $dst, $src2">, TB; @@ -660,10 +693,14 @@ } // end Two Address instructions // These are suprisingly enough not two address instructions! -def IMUL16rri : Ii16 <0x69, MRMSrcReg, (ops R16:$dst, R16:$src1, i16imm:$src2), "imul $dst, $src1, $src2">, OpSize; // R16 = R16*I16 -def IMUL32rri : Ii32 <0x69, MRMSrcReg, (ops R32:$dst, R32:$src1, i32imm:$src2), "imul $dst, $src1, $src2">; // R32 = R32*I32 -def IMUL16rri8 : Ii8 <0x6B, MRMSrcReg, (ops R16:$dst, R16:$src1, i8imm:$src2), "imul $dst, $src1, $src2">, OpSize; // R16 = R16*I8 -def IMUL32rri8 : Ii8 <0x6B, MRMSrcReg, (ops R32:$dst, R32:$src1, i8imm:$src2), "imul $dst, $src1, $src2">; // R32 = R32*I8 +def IMUL16rri : Ii16<0x69, MRMSrcReg, (ops R16:$dst, R16:$src1, i16imm:$src2), + "imul $dst, $src1, $src2">, OpSize; // R16 = R16*I16 +def IMUL32rri : Ii32<0x69, MRMSrcReg, (ops R32:$dst, R32:$src1, i32imm:$src2), + "imul $dst, $src1, $src2">; // R32 = R32*I32 +def IMUL16rri8 : Ii8<0x6B, MRMSrcReg, (ops R16:$dst, R16:$src1, i8imm:$src2), + "imul $dst, $src1, $src2">, OpSize; // R16 = R16*I8 +def IMUL32rri8 : Ii8<0x6B, MRMSrcReg, (ops R32:$dst, R32:$src1, i8imm:$src2), + "imul $dst, $src1, $src2">; // 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 @@ -671,9 +708,12 @@ //===----------------------------------------------------------------------===// // Test instructions are just like AND, except they don't generate a result. -def TEST8rr : I<0x84, MRMDestReg, (ops R8:$src1, R8:$src2), "test $src1, $src2">; -def TEST16rr : I<0x85, MRMDestReg, (ops R16:$src1, R16:$src2), "test $src1, $src2">, OpSize; -def TEST32rr : I<0x85, MRMDestReg, (ops R32:$src1, R32:$src2), "test $src1, $src2">; +def TEST8rr : I<0x84, MRMDestReg, (ops R8:$src1, R8:$src2), + "test $src1, $src2">; +def TEST16rr : I<0x85, MRMDestReg, (ops R16:$src1, R16:$src2), + "test $src1, $src2">, OpSize; +def TEST32rr : I<0x85, MRMDestReg, (ops R32:$src1, R32:$src2), + "test $src1, $src2">; 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 @@ -681,9 +721,12 @@ def TEST16rm : Im16 <"test", 0x85, MRMSrcMem >, OpSize; // flags = R16 & [mem16] def TEST32rm : Im32 <"test", 0x85, MRMSrcMem >; // flags = R32 & [mem32] -def TEST8ri : Ii8 <0xF6, MRM0r, (ops R8:$dst, i8imm:$src), "test $dst, $src">; // flags = R8 & imm8 -def TEST16ri : Ii16 <0xF7, MRM0r, (ops R16:$dst, i16imm:$src), "test $dst, $src">, OpSize; // flags = R16 & imm16 -def TEST32ri : Ii32 <0xF7, MRM0r, (ops R32:$dst, i32imm:$src), "test $dst, $src">; // flags = R32 & imm32 +def TEST8ri : Ii8 <0xF6, MRM0r, (ops R8:$dst, i8imm:$src), + "test $dst, $src">; // flags = R8 & imm8 +def TEST16ri : Ii16 <0xF7, MRM0r, (ops R16:$dst, i16imm:$src), + "test $dst, $src">, OpSize; // flags = R16 & imm16 +def TEST32ri : Ii32 <0xF7, MRM0r, (ops R32:$dst, i32imm:$src), + "test $dst, $src">; // 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 @@ -731,9 +774,9 @@ 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 <0x80, MRM7r, (ops R16:$dst, i8imm:$src), "cmp $dst, $src">; // compare R8, imm8 -def CMP16ri : Ii16 <0x81, MRM7r, (ops R16:$dst, i16imm:$src), "cmp $dst, $src">, OpSize; // compare R16, imm16 -def CMP32ri : Ii32 <0x81, MRM7r, (ops R32:$dst, i32imm:$src), "cmp $dst, $src">; // compare R32, imm32 +def CMP8ri : Ii8 <0x80, MRM7r, (ops R16:$dst, i8imm:$src), "cmp $dst, $src">; +def CMP16ri : Ii16 <0x81, MRM7r, (ops R16:$dst, i16imm:$src), "cmp $dst, $src">, OpSize; +def CMP32ri : Ii32 <0x81, MRM7r, (ops R32:$dst, i32imm:$src), "cmp $dst, $src">; 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 From brukman at cs.uiuc.edu Tue Aug 10 16:24:54 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 16:24:54 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPC.td Message-ID: <200408102124.QAA19491@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPC.td updated: 1.5 -> 1.6 --- Log message: * Fix file header to use tablegen emacs mode instead of c++ * Wrap long line to 80 cols --- Diffs of the changes: (+3 -2) Index: llvm/lib/Target/PowerPC/PowerPC.td diff -u llvm/lib/Target/PowerPC/PowerPC.td:1.5 llvm/lib/Target/PowerPC/PowerPC.td:1.6 --- llvm/lib/Target/PowerPC/PowerPC.td:1.5 Fri Aug 6 01:58:50 2004 +++ llvm/lib/Target/PowerPC/PowerPC.td Tue Aug 10 16:24:44 2004 @@ -1,4 +1,4 @@ -//===- PowerPC.td - Describe the PowerPC Target Machine ---------*- C++ -*-===// +//===- PowerPC.td - Describe the PowerPC Target Machine ----*- tablegen -*-===// // // The LLVM Compiler Infrastructure // @@ -24,7 +24,8 @@ def PowerPCInstrInfo : InstrInfo { let PHIInst = PHI; - let TSFlagsFields = ["ArgCount", "Arg0Type", "Arg1Type", "Arg2Type", "Arg3Type", "Arg4Type", "VMX", "PPC64"]; + let TSFlagsFields = ["ArgCount", "Arg0Type", "Arg1Type", "Arg2Type", + "Arg3Type", "Arg4Type", "VMX", "PPC64"]; let TSFlagsShifts = [ 0, 3, 8, 13, 18, 23, 28, 29 ]; } From brukman at cs.uiuc.edu Tue Aug 10 17:47:13 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 17:47:13 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCAsmPrinter.cpp PowerPCBranchSelector.cpp PowerPCISelSimple.cpp PowerPCInstrFormats.td PowerPCInstrInfo.cpp PowerPCInstrInfo.h PowerPCPEI.cpp PowerPCRegisterInfo.cpp PowerPCRegisterInfo.td Message-ID: <200408102247.RAA20656@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCAsmPrinter.cpp updated: 1.32 -> 1.33 PowerPCBranchSelector.cpp updated: 1.2 -> 1.3 PowerPCISelSimple.cpp updated: 1.55 -> 1.56 PowerPCInstrFormats.td updated: 1.8 -> 1.9 PowerPCInstrInfo.cpp updated: 1.6 -> 1.7 PowerPCInstrInfo.h updated: 1.3 -> 1.4 PowerPCPEI.cpp updated: 1.2 -> 1.3 PowerPCRegisterInfo.cpp updated: 1.25 -> 1.26 PowerPCRegisterInfo.td updated: 1.7 -> 1.8 --- Log message: Renamed PPC32 (namespace for regs, opcodes) to PPC to include 64-bit targets --- Diffs of the changes: (+461 -461) Index: llvm/lib/Target/PowerPC/PowerPCAsmPrinter.cpp diff -u llvm/lib/Target/PowerPC/PowerPCAsmPrinter.cpp:1.32 llvm/lib/Target/PowerPC/PowerPCAsmPrinter.cpp:1.33 --- llvm/lib/Target/PowerPC/PowerPCAsmPrinter.cpp:1.32 Mon Aug 9 17:27:45 2004 +++ llvm/lib/Target/PowerPC/PowerPCAsmPrinter.cpp Tue Aug 10 17:47:03 2004 @@ -478,16 +478,16 @@ void Printer::printImmOp(const MachineOperand &MO, unsigned ArgType) { int Imm = MO.getImmedValue(); - if (ArgType == PPC32II::Simm16 || ArgType == PPC32II::Disimm16) { + if (ArgType == PPCII::Simm16 || ArgType == PPCII::Disimm16) { O << (short)Imm; - } else if (ArgType == PPC32II::Zimm16) { + } else if (ArgType == PPCII::Zimm16) { O << (unsigned short)Imm; } else { O << Imm; } } -/// printMachineInstruction -- Print out a single PPC32 LLVM instruction +/// printMachineInstruction -- Print out a single PPC LLVM instruction /// MI in Darwin syntax to the current output stream. /// void Printer::printMachineInstruction(const MachineInstr *MI) { @@ -498,15 +498,15 @@ unsigned ArgCount = MI->getNumOperands(); unsigned ArgType[] = { - (Desc.TSFlags >> PPC32II::Arg0TypeShift) & PPC32II::ArgTypeMask, - (Desc.TSFlags >> PPC32II::Arg1TypeShift) & PPC32II::ArgTypeMask, - (Desc.TSFlags >> PPC32II::Arg2TypeShift) & PPC32II::ArgTypeMask, - (Desc.TSFlags >> PPC32II::Arg3TypeShift) & PPC32II::ArgTypeMask, - (Desc.TSFlags >> PPC32II::Arg4TypeShift) & PPC32II::ArgTypeMask + (Desc.TSFlags >> PPCII::Arg0TypeShift) & PPCII::ArgTypeMask, + (Desc.TSFlags >> PPCII::Arg1TypeShift) & PPCII::ArgTypeMask, + (Desc.TSFlags >> PPCII::Arg2TypeShift) & PPCII::ArgTypeMask, + (Desc.TSFlags >> PPCII::Arg3TypeShift) & PPCII::ArgTypeMask, + (Desc.TSFlags >> PPCII::Arg4TypeShift) & PPCII::ArgTypeMask }; - assert(((Desc.TSFlags & PPC32II::VMX) == 0) && + assert(((Desc.TSFlags & PPCII::VMX) == 0) && "Instruction requires VMX support"); - assert(((Desc.TSFlags & PPC32II::PPC64) == 0) && + assert(((Desc.TSFlags & PPCII::PPC64) == 0) && "Instruction requires 64 bit support"); ++EmittedInsts; @@ -514,27 +514,27 @@ // appropriate number of args that the assembler expects. This is because // may have many arguments appended to record the uses of registers that are // holding arguments to the called function. - if (Opcode == PPC32::COND_BRANCH) { + if (Opcode == PPC::COND_BRANCH) { std::cerr << "Error: untranslated conditional branch psuedo instruction!\n"; abort(); - } else if (Opcode == PPC32::IMPLICIT_DEF) { + } else if (Opcode == PPC::IMPLICIT_DEF) { O << "; IMPLICIT DEF "; printOp(MI->getOperand(0)); O << "\n"; return; - } else if (Opcode == PPC32::CALLpcrel) { + } else if (Opcode == PPC::CALLpcrel) { O << TII.getName(Opcode) << " "; printOp(MI->getOperand(0)); O << "\n"; return; - } else if (Opcode == PPC32::CALLindirect) { + } else if (Opcode == PPC::CALLindirect) { O << TII.getName(Opcode) << " "; printImmOp(MI->getOperand(0), ArgType[0]); O << ", "; printImmOp(MI->getOperand(1), ArgType[0]); O << "\n"; return; - } else if (Opcode == PPC32::MovePCtoLR) { + } else if (Opcode == PPC::MovePCtoLR) { // FIXME: should probably be converted to cout.width and cout.fill O << "bl \"L0000" << LabelNumber << "$pb\"\n"; O << "\"L0000" << LabelNumber << "$pb\":\n"; @@ -545,34 +545,34 @@ } O << TII.getName(Opcode) << " "; - if (Opcode == PPC32::LOADLoDirect || Opcode == PPC32::LOADLoIndirect) { + if (Opcode == PPC::LOADLoDirect || Opcode == PPC::LOADLoIndirect) { printOp(MI->getOperand(0)); O << ", lo16("; printOp(MI->getOperand(2)); O << "-\"L0000" << LabelNumber << "$pb\")"; O << "("; - if (MI->getOperand(1).getReg() == PPC32::R0) + if (MI->getOperand(1).getReg() == PPC::R0) O << "0"; else printOp(MI->getOperand(1)); O << ")\n"; - } else if (Opcode == PPC32::LOADHiAddr) { + } else if (Opcode == PPC::LOADHiAddr) { printOp(MI->getOperand(0)); O << ", "; - if (MI->getOperand(1).getReg() == PPC32::R0) + if (MI->getOperand(1).getReg() == PPC::R0) O << "0"; else printOp(MI->getOperand(1)); O << ", ha16(" ; printOp(MI->getOperand(2)); O << "-\"L0000" << LabelNumber << "$pb\")\n"; - } else if (ArgCount == 3 && ArgType[1] == PPC32II::Disimm16) { + } else if (ArgCount == 3 && ArgType[1] == PPCII::Disimm16) { printOp(MI->getOperand(0)); O << ", "; printImmOp(MI->getOperand(1), ArgType[1]); O << "("; if (MI->getOperand(2).hasAllocatedReg() && - MI->getOperand(2).getReg() == PPC32::R0) + MI->getOperand(2).getReg() == PPC::R0) O << "0"; else printOp(MI->getOperand(2)); @@ -580,9 +580,9 @@ } else { for (i = 0; i < ArgCount; ++i) { // addi and friends - if (i == 1 && ArgCount == 3 && ArgType[2] == PPC32II::Simm16 && + if (i == 1 && ArgCount == 3 && ArgType[2] == PPCII::Simm16 && MI->getOperand(1).hasAllocatedReg() && - MI->getOperand(1).getReg() == PPC32::R0) { + MI->getOperand(1).getReg() == PPC::R0) { O << "0"; // for long branch support, bc $+8 } else if (i == 1 && ArgCount == 2 && MI->getOperand(1).isImmediate() && Index: llvm/lib/Target/PowerPC/PowerPCBranchSelector.cpp diff -u llvm/lib/Target/PowerPC/PowerPCBranchSelector.cpp:1.2 llvm/lib/Target/PowerPC/PowerPCBranchSelector.cpp:1.3 --- llvm/lib/Target/PowerPC/PowerPCBranchSelector.cpp:1.2 Wed Jul 28 14:13:07 2004 +++ llvm/lib/Target/PowerPC/PowerPCBranchSelector.cpp Tue Aug 10 17:47:03 2004 @@ -35,17 +35,17 @@ /// static unsigned bytesForOpcode(unsigned opcode) { switch (opcode) { - case PPC32::COND_BRANCH: + case PPC::COND_BRANCH: // while this will be 4 most of the time, if we emit 12 it is just a // minor pessimization that saves us from having to worry about // keeping the offsets up to date later when we emit long branch glue. return 12; - case PPC32::MovePCtoLR: + case PPC::MovePCtoLR: // MovePCtoLR is actually a combination of a branch-and-link (bl) // followed by a move from link register to dest reg (mflr) return 8; break; - case PPC32::IMPLICIT_DEF: // no asm emitted + case PPC::IMPLICIT_DEF: // no asm emitted return 0; break; default: @@ -91,7 +91,7 @@ for (MachineBasicBlock::iterator MBBI = MBB->begin(), EE = MBB->end(); MBBI != EE; ++MBBI) { - if (MBBI->getOpcode() == PPC32::COND_BRANCH) { + if (MBBI->getOpcode() == PPC::COND_BRANCH) { // condbranch operands: // 0. CR0 register // 1. bc opcode @@ -108,11 +108,11 @@ MachineInstr *MI = MBBI; if (Displacement >= -32768 && Displacement <= 32767) { - BuildMI(*MBB, MBBI, Opcode, 2).addReg(PPC32::CR0).addMBB(trueMBB); + BuildMI(*MBB, MBBI, Opcode, 2).addReg(PPC::CR0).addMBB(trueMBB); } else { - BuildMI(*MBB, MBBI, Inverted, 2).addReg(PPC32::CR0).addSImm(8); - BuildMI(*MBB, MBBI, PPC32::B, 1).addMBB(trueMBB); - BuildMI(*MBB, MBBI, PPC32::B, 1).addMBB(falseMBB); + BuildMI(*MBB, MBBI, Inverted, 2).addReg(PPC::CR0).addSImm(8); + BuildMI(*MBB, MBBI, PPC::B, 1).addMBB(trueMBB); + BuildMI(*MBB, MBBI, PPC::B, 1).addMBB(falseMBB); } MBB->erase(MI); } Index: llvm/lib/Target/PowerPC/PowerPCISelSimple.cpp diff -u llvm/lib/Target/PowerPC/PowerPCISelSimple.cpp:1.55 llvm/lib/Target/PowerPC/PowerPCISelSimple.cpp:1.56 --- llvm/lib/Target/PowerPC/PowerPCISelSimple.cpp:1.55 Tue Aug 10 15:42:36 2004 +++ llvm/lib/Target/PowerPC/PowerPCISelSimple.cpp Tue Aug 10 17:47:03 2004 @@ -443,7 +443,7 @@ } else if (AllocaInst *AI = dyn_castFixedAlloca(V)) { unsigned Reg = makeAnotherReg(V->getType()); unsigned FI = getFixedSizedAllocaFI(AI); - addFrameReference(BuildMI(*MBB, IPt, PPC32::ADDI, 2, Reg), FI, 0, false); + addFrameReference(BuildMI(*MBB, IPt, PPC::ADDI, 2, Reg), FI, 0, false); return Reg; } @@ -530,13 +530,13 @@ MachineBasicBlock &FirstMBB = F->front(); MachineBasicBlock::iterator MBBI = FirstMBB.begin(); GlobalBaseReg = makeAnotherReg(Type::IntTy); - BuildMI(FirstMBB, MBBI, PPC32::IMPLICIT_DEF, 0, PPC32::LR); - BuildMI(FirstMBB, MBBI, PPC32::MovePCtoLR, 0, GlobalBaseReg); + BuildMI(FirstMBB, MBBI, PPC::IMPLICIT_DEF, 0, PPC::LR); + BuildMI(FirstMBB, MBBI, PPC::MovePCtoLR, 0, GlobalBaseReg); GlobalBaseInitialized = true; } // Emit our copy of GlobalBaseReg to the destination register in the // current MBB - BuildMI(*MBB, IP, PPC32::OR, 2, R).addReg(GlobalBaseReg) + BuildMI(*MBB, IP, PPC::OR, 2, R).addReg(GlobalBaseReg) .addReg(GlobalBaseReg); } @@ -578,7 +578,7 @@ // Handle bool if (C->getType() == Type::BoolTy) { - BuildMI(*MBB, IP, PPC32::LI, 1, R).addSImm(C == ConstantBool::True); + BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(C == ConstantBool::True); return; } @@ -586,21 +586,21 @@ if (ConstantUInt *CUI = dyn_cast(C)) { unsigned uval = CUI->getValue(); if (uval < 32768) { - BuildMI(*MBB, IP, PPC32::LI, 1, R).addSImm(uval); + BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(uval); } else { unsigned Temp = makeAnotherReg(Type::IntTy); - BuildMI(*MBB, IP, PPC32::LIS, 1, Temp).addSImm(uval >> 16); - BuildMI(*MBB, IP, PPC32::ORI, 2, R).addReg(Temp).addImm(uval); + BuildMI(*MBB, IP, PPC::LIS, 1, Temp).addSImm(uval >> 16); + BuildMI(*MBB, IP, PPC::ORI, 2, R).addReg(Temp).addImm(uval); } return; } else if (ConstantSInt *CSI = dyn_cast(C)) { int sval = CSI->getValue(); if (sval < 32768 && sval >= -32768) { - BuildMI(*MBB, IP, PPC32::LI, 1, R).addSImm(sval); + BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(sval); } else { unsigned Temp = makeAnotherReg(Type::IntTy); - BuildMI(*MBB, IP, PPC32::LIS, 1, Temp).addSImm(sval >> 16); - BuildMI(*MBB, IP, PPC32::ORI, 2, R).addReg(Temp).addImm(sval); + BuildMI(*MBB, IP, PPC::LIS, 1, Temp).addSImm(sval >> 16); + BuildMI(*MBB, IP, PPC::ORI, 2, R).addReg(Temp).addImm(sval); } return; } @@ -621,26 +621,26 @@ unsigned Reg2 = makeAnotherReg(Type::IntTy); // Move value at base + distance into return reg copyGlobalBaseToRegister(MBB, IP, GlobalBase); - BuildMI(*MBB, IP, PPC32::LOADHiAddr, 2, Reg1).addReg(GlobalBase) + BuildMI(*MBB, IP, PPC::LOADHiAddr, 2, Reg1).addReg(GlobalBase) .addConstantPoolIndex(CPI); - BuildMI(*MBB, IP, PPC32::LOADLoDirect, 2, Reg2).addReg(Reg1) + BuildMI(*MBB, IP, PPC::LOADLoDirect, 2, Reg2).addReg(Reg1) .addConstantPoolIndex(CPI); - unsigned LoadOpcode = (Ty == Type::FloatTy) ? PPC32::LFS : PPC32::LFD; + unsigned LoadOpcode = (Ty == Type::FloatTy) ? PPC::LFS : PPC::LFD; BuildMI(*MBB, IP, LoadOpcode, 2, R).addSImm(0).addReg(Reg2); } else if (isa(C)) { // Copy zero (null pointer) to the register. - BuildMI(*MBB, IP, PPC32::LI, 1, R).addSImm(0); + BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(0); } else if (GlobalValue *GV = dyn_cast(C)) { // GV is located at base + distance unsigned GlobalBase = makeAnotherReg(Type::IntTy); unsigned TmpReg = makeAnotherReg(GV->getType()); unsigned Opcode = (GV->hasWeakLinkage() || GV->isExternal()) ? - PPC32::LOADLoIndirect : PPC32::LOADLoDirect; + PPC::LOADLoIndirect : PPC::LOADLoDirect; // Move value at base + distance into return reg copyGlobalBaseToRegister(MBB, IP, GlobalBase); - BuildMI(*MBB, IP, PPC32::LOADHiAddr, 2, TmpReg).addReg(GlobalBase) + BuildMI(*MBB, IP, PPC::LOADHiAddr, 2, TmpReg).addReg(GlobalBase) .addGlobalAddress(GV); BuildMI(*MBB, IP, Opcode, 2, R).addReg(TmpReg).addGlobalAddress(GV); @@ -660,12 +660,12 @@ unsigned FPR_remaining = 13; unsigned GPR_idx = 0, FPR_idx = 0; static const unsigned GPR[] = { - PPC32::R3, PPC32::R4, PPC32::R5, PPC32::R6, - PPC32::R7, PPC32::R8, PPC32::R9, PPC32::R10, + PPC::R3, PPC::R4, PPC::R5, PPC::R6, + PPC::R7, PPC::R8, PPC::R9, PPC::R10, }; static const unsigned FPR[] = { - PPC32::F1, PPC32::F2, PPC32::F3, PPC32::F4, PPC32::F5, PPC32::F6, PPC32::F7, - PPC32::F8, PPC32::F9, PPC32::F10, PPC32::F11, PPC32::F12, PPC32::F13 + PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, PPC::F7, + PPC::F8, PPC::F9, PPC::F10, PPC::F11, PPC::F12, PPC::F13 }; MachineFrameInfo *MFI = F->getFrameInfo(); @@ -680,11 +680,11 @@ if (ArgLive) { FI = MFI->CreateFixedObject(4, ArgOffset); if (GPR_remaining > 0) { - BuildMI(BB, PPC32::IMPLICIT_DEF, 0, GPR[GPR_idx]); - BuildMI(BB, PPC32::OR, 2, Reg).addReg(GPR[GPR_idx]) + BuildMI(BB, PPC::IMPLICIT_DEF, 0, GPR[GPR_idx]); + BuildMI(BB, PPC::OR, 2, Reg).addReg(GPR[GPR_idx]) .addReg(GPR[GPR_idx]); } else { - addFrameReference(BuildMI(BB, PPC32::LBZ, 2, Reg), FI); + addFrameReference(BuildMI(BB, PPC::LBZ, 2, Reg), FI); } } break; @@ -692,11 +692,11 @@ if (ArgLive) { FI = MFI->CreateFixedObject(4, ArgOffset); if (GPR_remaining > 0) { - BuildMI(BB, PPC32::IMPLICIT_DEF, 0, GPR[GPR_idx]); - BuildMI(BB, PPC32::OR, 2, Reg).addReg(GPR[GPR_idx]) + BuildMI(BB, PPC::IMPLICIT_DEF, 0, GPR[GPR_idx]); + BuildMI(BB, PPC::OR, 2, Reg).addReg(GPR[GPR_idx]) .addReg(GPR[GPR_idx]); } else { - addFrameReference(BuildMI(BB, PPC32::LHZ, 2, Reg), FI); + addFrameReference(BuildMI(BB, PPC::LHZ, 2, Reg), FI); } } break; @@ -704,11 +704,11 @@ if (ArgLive) { FI = MFI->CreateFixedObject(4, ArgOffset); if (GPR_remaining > 0) { - BuildMI(BB, PPC32::IMPLICIT_DEF, 0, GPR[GPR_idx]); - BuildMI(BB, PPC32::OR, 2, Reg).addReg(GPR[GPR_idx]) + BuildMI(BB, PPC::IMPLICIT_DEF, 0, GPR[GPR_idx]); + BuildMI(BB, PPC::OR, 2, Reg).addReg(GPR[GPR_idx]) .addReg(GPR[GPR_idx]); } else { - addFrameReference(BuildMI(BB, PPC32::LWZ, 2, Reg), FI); + addFrameReference(BuildMI(BB, PPC::LWZ, 2, Reg), FI); } } break; @@ -716,15 +716,15 @@ if (ArgLive) { FI = MFI->CreateFixedObject(8, ArgOffset); if (GPR_remaining > 1) { - BuildMI(BB, PPC32::IMPLICIT_DEF, 0, GPR[GPR_idx]); - BuildMI(BB, PPC32::IMPLICIT_DEF, 0, GPR[GPR_idx+1]); - BuildMI(BB, PPC32::OR, 2, Reg).addReg(GPR[GPR_idx]) + BuildMI(BB, PPC::IMPLICIT_DEF, 0, GPR[GPR_idx]); + BuildMI(BB, PPC::IMPLICIT_DEF, 0, GPR[GPR_idx+1]); + BuildMI(BB, PPC::OR, 2, Reg).addReg(GPR[GPR_idx]) .addReg(GPR[GPR_idx]); - BuildMI(BB, PPC32::OR, 2, Reg+1).addReg(GPR[GPR_idx+1]) + BuildMI(BB, PPC::OR, 2, Reg+1).addReg(GPR[GPR_idx+1]) .addReg(GPR[GPR_idx+1]); } else { - addFrameReference(BuildMI(BB, PPC32::LWZ, 2, Reg), FI); - addFrameReference(BuildMI(BB, PPC32::LWZ, 2, Reg+1), FI, 4); + addFrameReference(BuildMI(BB, PPC::LWZ, 2, Reg), FI); + addFrameReference(BuildMI(BB, PPC::LWZ, 2, Reg+1), FI, 4); } } // longs require 4 additional bytes and use 2 GPRs @@ -739,12 +739,12 @@ FI = MFI->CreateFixedObject(4, ArgOffset); if (FPR_remaining > 0) { - BuildMI(BB, PPC32::IMPLICIT_DEF, 0, FPR[FPR_idx]); - BuildMI(BB, PPC32::FMR, 1, Reg).addReg(FPR[FPR_idx]); + BuildMI(BB, PPC::IMPLICIT_DEF, 0, FPR[FPR_idx]); + BuildMI(BB, PPC::FMR, 1, Reg).addReg(FPR[FPR_idx]); FPR_remaining--; FPR_idx++; } else { - addFrameReference(BuildMI(BB, PPC32::LFS, 2, Reg), FI); + addFrameReference(BuildMI(BB, PPC::LFS, 2, Reg), FI); } } break; @@ -753,12 +753,12 @@ FI = MFI->CreateFixedObject(8, ArgOffset); if (FPR_remaining > 0) { - BuildMI(BB, PPC32::IMPLICIT_DEF, 0, FPR[FPR_idx]); - BuildMI(BB, PPC32::FMR, 1, Reg).addReg(FPR[FPR_idx]); + BuildMI(BB, PPC::IMPLICIT_DEF, 0, FPR[FPR_idx]); + BuildMI(BB, PPC::FMR, 1, Reg).addReg(FPR[FPR_idx]); FPR_remaining--; FPR_idx++; } else { - addFrameReference(BuildMI(BB, PPC32::LFD, 2, Reg), FI); + addFrameReference(BuildMI(BB, PPC::LFD, 2, Reg), FI); } } @@ -806,12 +806,12 @@ // Create a new machine instr PHI node, and insert it. unsigned PHIReg = getReg(*PN); MachineInstr *PhiMI = BuildMI(MBB, PHIInsertPoint, - PPC32::PHI, PN->getNumOperands(), PHIReg); + PPC::PHI, PN->getNumOperands(), PHIReg); MachineInstr *LongPhiMI = 0; if (PN->getType() == Type::LongTy || PN->getType() == Type::ULongTy) LongPhiMI = BuildMI(MBB, PHIInsertPoint, - PPC32::PHI, PN->getNumOperands(), PHIReg+1); + PPC::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, @@ -858,7 +858,7 @@ MachineBasicBlock::iterator PI = PredMBB->begin(); // Skip over any PHI nodes though! - while (PI != PredMBB->end() && PI->getOpcode() == PPC32::PHI) + while (PI != PredMBB->end() && PI->getOpcode() == PPC::PHI) ++PI; ValReg = getReg(Val, PredMBB, PI); @@ -948,19 +948,19 @@ static unsigned getPPCOpcodeForSetCCNumber(unsigned Opcode) { switch (Opcode) { default: assert(0 && "Unknown setcc instruction!"); - case Instruction::SetEQ: return PPC32::BEQ; - case Instruction::SetNE: return PPC32::BNE; - case Instruction::SetLT: return PPC32::BLT; - case Instruction::SetGE: return PPC32::BGE; - case Instruction::SetGT: return PPC32::BGT; - case Instruction::SetLE: return PPC32::BLE; + case Instruction::SetEQ: return PPC::BEQ; + case Instruction::SetNE: return PPC::BNE; + case Instruction::SetLT: return PPC::BLT; + case Instruction::SetGE: return PPC::BGE; + case Instruction::SetGT: return PPC::BGT; + case Instruction::SetLE: return PPC::BLE; } } /// emitUCOM - emits an unordered FP compare. void ISel::emitUCOM(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP, unsigned LHS, unsigned RHS) { - BuildMI(*MBB, IP, PPC32::FCMPU, 2, PPC32::CR0).addReg(LHS).addReg(RHS); + BuildMI(*MBB, IP, PPC::FCMPU, 2, PPC::CR0).addReg(LHS).addReg(RHS); } /// EmitComparison - emits a comparison of the two operands, returning the @@ -979,29 +979,29 @@ if (Class == cByte) { unsigned TmpReg = makeAnotherReg(CompTy); if (CompTy->isSigned()) - BuildMI(*MBB, IP, PPC32::EXTSB, 1, TmpReg).addReg(Op0r); + BuildMI(*MBB, IP, PPC::EXTSB, 1, TmpReg).addReg(Op0r); else - BuildMI(*MBB, IP, PPC32::RLWINM, 4, TmpReg).addReg(Op0r).addImm(0) + BuildMI(*MBB, IP, PPC::RLWINM, 4, TmpReg).addReg(Op0r).addImm(0) .addImm(24).addImm(31); Op0r = TmpReg; } else if (Class == cShort) { unsigned TmpReg = makeAnotherReg(CompTy); if (CompTy->isSigned()) - BuildMI(*MBB, IP, PPC32::EXTSH, 1, TmpReg).addReg(Op0r); + BuildMI(*MBB, IP, PPC::EXTSH, 1, TmpReg).addReg(Op0r); else - BuildMI(*MBB, IP, PPC32::RLWINM, 4, TmpReg).addReg(Op0r).addImm(0) + BuildMI(*MBB, IP, PPC::RLWINM, 4, TmpReg).addReg(Op0r).addImm(0) .addImm(16).addImm(31); Op0r = TmpReg; } // Use crand for lt, gt and crandc for le, ge - unsigned CROpcode = (OpNum == 2 || OpNum == 4) ? PPC32::CRAND : PPC32::CRANDC; + unsigned CROpcode = (OpNum == 2 || OpNum == 4) ? PPC::CRAND : PPC::CRANDC; // ? cr1[lt] : cr1[gt] unsigned CR1field = (OpNum == 2 || OpNum == 3) ? 4 : 5; // ? cr0[lt] : cr0[gt] unsigned CR0field = (OpNum == 2 || OpNum == 5) ? 0 : 1; - unsigned Opcode = CompTy->isSigned() ? PPC32::CMPW : PPC32::CMPLW; - unsigned OpcodeImm = CompTy->isSigned() ? PPC32::CMPWI : PPC32::CMPLWI; + unsigned Opcode = CompTy->isSigned() ? PPC::CMPW : PPC::CMPLW; + unsigned OpcodeImm = CompTy->isSigned() ? PPC::CMPWI : PPC::CMPLWI; // Special case handling of: cmp R, i if (ConstantInt *CI = dyn_cast(Op1)) { @@ -1010,10 +1010,10 @@ // Treat compare like ADDI for the purposes of immediate suitability if (canUseAsImmediateForOpcode(CI, 0)) { - BuildMI(*MBB, IP, OpcodeImm, 2, PPC32::CR0).addReg(Op0r).addSImm(Op1v); + BuildMI(*MBB, IP, OpcodeImm, 2, PPC::CR0).addReg(Op0r).addSImm(Op1v); } else { unsigned Op1r = getReg(Op1, MBB, IP); - BuildMI(*MBB, IP, Opcode, 2, PPC32::CR0).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, Opcode, 2, PPC::CR0).addReg(Op0r).addReg(Op1r); } return OpNum; } else { @@ -1027,27 +1027,27 @@ unsigned HiTmp = makeAnotherReg(Type::IntTy); unsigned FinalTmp = makeAnotherReg(Type::IntTy); - BuildMI(*MBB, IP, PPC32::XORI, 2, LoLow).addReg(Op0r+1) + BuildMI(*MBB, IP, PPC::XORI, 2, LoLow).addReg(Op0r+1) .addImm(LowCst & 0xFFFF); - BuildMI(*MBB, IP, PPC32::XORIS, 2, LoTmp).addReg(LoLow) + BuildMI(*MBB, IP, PPC::XORIS, 2, LoTmp).addReg(LoLow) .addImm(LowCst >> 16); - BuildMI(*MBB, IP, PPC32::XORI, 2, HiLow).addReg(Op0r) + BuildMI(*MBB, IP, PPC::XORI, 2, HiLow).addReg(Op0r) .addImm(HiCst & 0xFFFF); - BuildMI(*MBB, IP, PPC32::XORIS, 2, HiTmp).addReg(HiLow) + BuildMI(*MBB, IP, PPC::XORIS, 2, HiTmp).addReg(HiLow) .addImm(HiCst >> 16); - BuildMI(*MBB, IP, PPC32::ORo, 2, FinalTmp).addReg(LoTmp).addReg(HiTmp); + BuildMI(*MBB, IP, PPC::ORo, 2, FinalTmp).addReg(LoTmp).addReg(HiTmp); return OpNum; } else { unsigned ConstReg = makeAnotherReg(CompTy); copyConstantToRegister(MBB, IP, CI, ConstReg); // cr0 = r3 ccOpcode r5 or (r3 == r5 AND r4 ccOpcode r6) - BuildMI(*MBB, IP, Opcode, 2, PPC32::CR0).addReg(Op0r) + BuildMI(*MBB, IP, Opcode, 2, PPC::CR0).addReg(Op0r) .addReg(ConstReg); - BuildMI(*MBB, IP, Opcode, 2, PPC32::CR1).addReg(Op0r+1) + BuildMI(*MBB, IP, Opcode, 2, PPC::CR1).addReg(Op0r+1) .addReg(ConstReg+1); - BuildMI(*MBB, IP, PPC32::CRAND, 3).addImm(2).addImm(2).addImm(CR1field); - BuildMI(*MBB, IP, PPC32::CROR, 3).addImm(CR0field).addImm(CR0field) + BuildMI(*MBB, IP, PPC::CRAND, 3).addImm(2).addImm(2).addImm(CR1field); + BuildMI(*MBB, IP, PPC::CROR, 3).addImm(CR0field).addImm(CR0field) .addImm(2); return OpNum; } @@ -1061,7 +1061,7 @@ case cByte: case cShort: case cInt: - BuildMI(*MBB, IP, Opcode, 2, PPC32::CR0).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, Opcode, 2, PPC::CR0).addReg(Op0r).addReg(Op1r); break; case cFP32: @@ -1074,19 +1074,19 @@ unsigned LoTmp = makeAnotherReg(Type::IntTy); unsigned HiTmp = makeAnotherReg(Type::IntTy); unsigned FinalTmp = makeAnotherReg(Type::IntTy); - BuildMI(*MBB, IP, PPC32::XOR, 2, HiTmp).addReg(Op0r).addReg(Op1r); - BuildMI(*MBB, IP, PPC32::XOR, 2, LoTmp).addReg(Op0r+1).addReg(Op1r+1); - BuildMI(*MBB, IP, PPC32::ORo, 2, FinalTmp).addReg(LoTmp).addReg(HiTmp); + BuildMI(*MBB, IP, PPC::XOR, 2, HiTmp).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, PPC::XOR, 2, LoTmp).addReg(Op0r+1).addReg(Op1r+1); + BuildMI(*MBB, IP, PPC::ORo, 2, FinalTmp).addReg(LoTmp).addReg(HiTmp); break; // Allow the sete or setne to be generated from flags set by OR } else { unsigned TmpReg1 = makeAnotherReg(Type::IntTy); unsigned TmpReg2 = makeAnotherReg(Type::IntTy); // cr0 = r3 ccOpcode r5 or (r3 == r5 AND r4 ccOpcode r6) - BuildMI(*MBB, IP, Opcode, 2, PPC32::CR0).addReg(Op0r).addReg(Op1r); - BuildMI(*MBB, IP, Opcode, 2, PPC32::CR1).addReg(Op0r+1).addReg(Op1r+1); - BuildMI(*MBB, IP, PPC32::CRAND, 3).addImm(2).addImm(2).addImm(CR1field); - BuildMI(*MBB, IP, PPC32::CROR, 3).addImm(CR0field).addImm(CR0field) + BuildMI(*MBB, IP, Opcode, 2, PPC::CR0).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, Opcode, 2, PPC::CR1).addReg(Op0r+1).addReg(Op1r+1); + BuildMI(*MBB, IP, PPC::CRAND, 3).addImm(2).addImm(2).addImm(CR1field); + BuildMI(*MBB, IP, PPC::CROR, 3).addImm(CR0field).addImm(CR0field) .addImm(2); return OpNum; } @@ -1124,10 +1124,10 @@ // bCC. But MBB->getFirstTerminator() can't understand this. MachineBasicBlock *copy1MBB = new MachineBasicBlock(LLVM_BB); F->getBasicBlockList().insert(It, copy1MBB); - BuildMI(BB, Opcode, 2).addReg(PPC32::CR0).addMBB(copy1MBB); + BuildMI(BB, Opcode, 2).addReg(PPC::CR0).addMBB(copy1MBB); MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB); F->getBasicBlockList().insert(It, copy0MBB); - BuildMI(BB, PPC32::B, 1).addMBB(copy0MBB); + BuildMI(BB, PPC::B, 1).addMBB(copy0MBB); MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB); F->getBasicBlockList().insert(It, sinkMBB); // Update machine-CFG edges @@ -1139,8 +1139,8 @@ // b sinkMBB BB = copy1MBB; unsigned TrueValue = makeAnotherReg(I.getType()); - BuildMI(BB, PPC32::LI, 1, TrueValue).addSImm(1); - BuildMI(BB, PPC32::B, 1).addMBB(sinkMBB); + BuildMI(BB, PPC::LI, 1, TrueValue).addSImm(1); + BuildMI(BB, PPC::B, 1).addMBB(sinkMBB); // Update machine-CFG edges BB->addSuccessor(sinkMBB); @@ -1149,7 +1149,7 @@ // fallthrough BB = copy0MBB; unsigned FalseValue = makeAnotherReg(I.getType()); - BuildMI(BB, PPC32::LI, 1, FalseValue).addSImm(0); + BuildMI(BB, PPC::LI, 1, FalseValue).addSImm(0); // Update machine-CFG edges BB->addSuccessor(sinkMBB); @@ -1157,7 +1157,7 @@ // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, copy1MBB ] // ... BB = sinkMBB; - BuildMI(BB, PPC32::PHI, 4, DestReg).addReg(FalseValue) + BuildMI(BB, PPC::PHI, 4, DestReg).addReg(FalseValue) .addMBB(copy0MBB).addReg(TrueValue).addMBB(copy1MBB); } @@ -1188,7 +1188,7 @@ Opcode = getPPCOpcodeForSetCCNumber(SCI->getOpcode()); } else { unsigned CondReg = getReg(Cond, MBB, IP); - BuildMI(*MBB, IP, PPC32::CMPI, 2, PPC32::CR0).addReg(CondReg).addSImm(0); + BuildMI(*MBB, IP, PPC::CMPI, 2, PPC::CR0).addReg(CondReg).addSImm(0); Opcode = getPPCOpcodeForSetCCNumber(Instruction::SetNE); } @@ -1208,10 +1208,10 @@ // bCC. But MBB->getFirstTerminator() can't understand this. MachineBasicBlock *copy1MBB = new MachineBasicBlock(LLVM_BB); F->getBasicBlockList().insert(It, copy1MBB); - BuildMI(BB, Opcode, 2).addReg(PPC32::CR0).addMBB(copy1MBB); + BuildMI(BB, Opcode, 2).addReg(PPC::CR0).addMBB(copy1MBB); MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB); F->getBasicBlockList().insert(It, copy0MBB); - BuildMI(BB, PPC32::B, 1).addMBB(copy0MBB); + BuildMI(BB, PPC::B, 1).addMBB(copy0MBB); MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB); F->getBasicBlockList().insert(It, sinkMBB); // Update machine-CFG edges @@ -1223,7 +1223,7 @@ // b sinkMBB BB = copy1MBB; unsigned TrueValue = getReg(TrueVal, BB, BB->begin()); - BuildMI(BB, PPC32::B, 1).addMBB(sinkMBB); + BuildMI(BB, PPC::B, 1).addMBB(sinkMBB); // Update machine-CFG edges BB->addSuccessor(sinkMBB); @@ -1239,11 +1239,11 @@ // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, copy1MBB ] // ... BB = sinkMBB; - BuildMI(BB, PPC32::PHI, 4, DestReg).addReg(FalseValue) + BuildMI(BB, PPC::PHI, 4, DestReg).addReg(FalseValue) .addMBB(copy0MBB).addReg(TrueValue).addMBB(copy1MBB); // For a register pair representing a long value, define the second reg if (getClass(TrueVal->getType()) == cLong) - BuildMI(BB, PPC32::LI, 1, DestReg+1).addImm(0); + BuildMI(BB, PPC::LI, 1, DestReg+1).addImm(0); return; } @@ -1268,11 +1268,11 @@ int TheVal = CI->getRawValue() & 0xFFFFFFFF; if (TheVal < 32768 && TheVal >= -32768) { - BuildMI(BB, PPC32::LI, 1, targetReg).addSImm(TheVal); + BuildMI(BB, PPC::LI, 1, targetReg).addSImm(TheVal); } else { unsigned TmpReg = makeAnotherReg(Type::IntTy); - BuildMI(BB, PPC32::LIS, 1, TmpReg).addSImm(TheVal >> 16); - BuildMI(BB, PPC32::ORI, 2, targetReg).addReg(TmpReg) + BuildMI(BB, PPC::LIS, 1, TmpReg).addSImm(TheVal >> 16); + BuildMI(BB, PPC::ORI, 2, targetReg).addReg(TmpReg) .addImm(TheVal & 0xFFFF); } return; @@ -1285,22 +1285,22 @@ case cByte: // Extend value into target register (8->32) if (isUnsigned) - BuildMI(BB, PPC32::RLWINM, 4, targetReg).addReg(Reg).addZImm(0) + BuildMI(BB, PPC::RLWINM, 4, targetReg).addReg(Reg).addZImm(0) .addZImm(24).addZImm(31); else - BuildMI(BB, PPC32::EXTSB, 1, targetReg).addReg(Reg); + BuildMI(BB, PPC::EXTSB, 1, targetReg).addReg(Reg); break; case cShort: // Extend value into target register (16->32) if (isUnsigned) - BuildMI(BB, PPC32::RLWINM, 4, targetReg).addReg(Reg).addZImm(0) + BuildMI(BB, PPC::RLWINM, 4, targetReg).addReg(Reg).addZImm(0) .addZImm(16).addZImm(31); else - BuildMI(BB, PPC32::EXTSH, 1, targetReg).addReg(Reg); + BuildMI(BB, PPC::EXTSH, 1, targetReg).addReg(Reg); break; case cInt: // Move value into target register (32->32) - BuildMI(BB, PPC32::OR, 2, targetReg).addReg(Reg).addReg(Reg); + BuildMI(BB, PPC::OR, 2, targetReg).addReg(Reg).addReg(Reg); break; default: assert(0 && "Unpromotable operand class in promote32"); @@ -1317,25 +1317,25 @@ case cByte: // integral return values: extend or move into r3 and return case cShort: case cInt: - promote32(PPC32::R3, ValueRecord(RetVal)); + promote32(PPC::R3, ValueRecord(RetVal)); break; case cFP32: case cFP64: { // Floats & Doubles: Return in f1 unsigned RetReg = getReg(RetVal); - BuildMI(BB, PPC32::FMR, 1, PPC32::F1).addReg(RetReg); + BuildMI(BB, PPC::FMR, 1, PPC::F1).addReg(RetReg); break; } case cLong: { unsigned RetReg = getReg(RetVal); - BuildMI(BB, PPC32::OR, 2, PPC32::R3).addReg(RetReg).addReg(RetReg); - BuildMI(BB, PPC32::OR, 2, PPC32::R4).addReg(RetReg+1).addReg(RetReg+1); + BuildMI(BB, PPC::OR, 2, PPC::R3).addReg(RetReg).addReg(RetReg); + BuildMI(BB, PPC::OR, 2, PPC::R4).addReg(RetReg+1).addReg(RetReg+1); break; } default: visitInstruction(I); } } - BuildMI(BB, PPC32::BLR, 1).addImm(0); + BuildMI(BB, PPC::BLR, 1).addImm(0); } // getBlockAfter - Return the basic block which occurs lexically after the @@ -1360,7 +1360,7 @@ if (!BI.isConditional()) { // Unconditional branch? if (BI.getSuccessor(0) != NextBB) - BuildMI(BB, PPC32::B, 1).addMBB(MBBMap[BI.getSuccessor(0)]); + BuildMI(BB, PPC::B, 1).addMBB(MBBMap[BI.getSuccessor(0)]); return; } @@ -1370,19 +1370,19 @@ // Nope, cannot fold setcc into this branch. Emit a branch on a condition // computed some other way... unsigned condReg = getReg(BI.getCondition()); - BuildMI(BB, PPC32::CMPLI, 3, PPC32::CR0).addImm(0).addReg(condReg) + BuildMI(BB, PPC::CMPLI, 3, PPC::CR0).addImm(0).addReg(condReg) .addImm(0); if (BI.getSuccessor(1) == NextBB) { if (BI.getSuccessor(0) != NextBB) - BuildMI(BB, PPC32::COND_BRANCH, 3).addReg(PPC32::CR0).addImm(PPC32::BNE) + BuildMI(BB, PPC::COND_BRANCH, 3).addReg(PPC::CR0).addImm(PPC::BNE) .addMBB(MBBMap[BI.getSuccessor(0)]) .addMBB(MBBMap[BI.getSuccessor(1)]); } else { - BuildMI(BB, PPC32::COND_BRANCH, 3).addReg(PPC32::CR0).addImm(PPC32::BEQ) + BuildMI(BB, PPC::COND_BRANCH, 3).addReg(PPC::CR0).addImm(PPC::BEQ) .addMBB(MBBMap[BI.getSuccessor(1)]) .addMBB(MBBMap[BI.getSuccessor(0)]); if (BI.getSuccessor(0) != NextBB) - BuildMI(BB, PPC32::B, 1).addMBB(MBBMap[BI.getSuccessor(0)]); + BuildMI(BB, PPC::B, 1).addMBB(MBBMap[BI.getSuccessor(0)]); } return; } @@ -1393,16 +1393,16 @@ OpNum = EmitComparison(OpNum, SCI->getOperand(0), SCI->getOperand(1), BB,MII); if (BI.getSuccessor(0) != NextBB) { - BuildMI(BB, PPC32::COND_BRANCH, 3).addReg(PPC32::CR0).addImm(Opcode) + BuildMI(BB, PPC::COND_BRANCH, 3).addReg(PPC::CR0).addImm(Opcode) .addMBB(MBBMap[BI.getSuccessor(0)]) .addMBB(MBBMap[BI.getSuccessor(1)]); if (BI.getSuccessor(1) != NextBB) - BuildMI(BB, PPC32::B, 1).addMBB(MBBMap[BI.getSuccessor(1)]); + BuildMI(BB, PPC::B, 1).addMBB(MBBMap[BI.getSuccessor(1)]); } else { // Change to the inverse condition... if (BI.getSuccessor(1) != NextBB) { Opcode = PowerPCInstrInfo::invertPPCBranchOpcode(Opcode); - BuildMI(BB, PPC32::COND_BRANCH, 3).addReg(PPC32::CR0).addImm(Opcode) + BuildMI(BB, PPC::COND_BRANCH, 3).addReg(PPC::CR0).addImm(Opcode) .addMBB(MBBMap[BI.getSuccessor(1)]) .addMBB(MBBMap[BI.getSuccessor(0)]); } @@ -1443,20 +1443,20 @@ // Adjust the stack pointer for the new arguments... // These functions are automatically eliminated by the prolog/epilog pass - BuildMI(BB, PPC32::ADJCALLSTACKDOWN, 1).addImm(NumBytes); + BuildMI(BB, PPC::ADJCALLSTACKDOWN, 1).addImm(NumBytes); // Arguments go on the stack in reverse order, as specified by the ABI. // Offset to the paramater area on the stack is 24. int GPR_remaining = 8, FPR_remaining = 13; unsigned GPR_idx = 0, FPR_idx = 0; static const unsigned GPR[] = { - PPC32::R3, PPC32::R4, PPC32::R5, PPC32::R6, - PPC32::R7, PPC32::R8, PPC32::R9, PPC32::R10, + PPC::R3, PPC::R4, PPC::R5, PPC::R6, + PPC::R7, PPC::R8, PPC::R9, PPC::R10, }; static const unsigned FPR[] = { - PPC32::F1, PPC32::F2, PPC32::F3, PPC32::F4, PPC32::F5, PPC32::F6, - PPC32::F7, PPC32::F8, PPC32::F9, PPC32::F10, PPC32::F11, PPC32::F12, - PPC32::F13 + PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, + PPC::F7, PPC::F8, PPC::F9, PPC::F10, PPC::F11, PPC::F12, + PPC::F13 }; for (unsigned i = 0, e = Args.size(); i != e; ++i) { @@ -1470,13 +1470,13 @@ // Reg or stack? if (GPR_remaining > 0) { - BuildMI(BB, PPC32::OR, 2, GPR[GPR_idx]).addReg(ArgReg) + BuildMI(BB, PPC::OR, 2, GPR[GPR_idx]).addReg(ArgReg) .addReg(ArgReg); CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use); } if (GPR_remaining <= 0 || isVarArg) { - BuildMI(BB, PPC32::STW, 3).addReg(ArgReg).addSImm(ArgOffset) - .addReg(PPC32::R1); + BuildMI(BB, PPC::STW, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); } break; case cInt: @@ -1484,13 +1484,13 @@ // Reg or stack? if (GPR_remaining > 0) { - BuildMI(BB, PPC32::OR, 2, GPR[GPR_idx]).addReg(ArgReg) + BuildMI(BB, PPC::OR, 2, GPR[GPR_idx]).addReg(ArgReg) .addReg(ArgReg); CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use); } if (GPR_remaining <= 0 || isVarArg) { - BuildMI(BB, PPC32::STW, 3).addReg(ArgReg).addSImm(ArgOffset) - .addReg(PPC32::R1); + BuildMI(BB, PPC::STW, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); } break; case cLong: @@ -1499,18 +1499,18 @@ // Reg or stack? Note that PPC calling conventions state that long args // are passed rN = hi, rN+1 = lo, opposite of LLVM. if (GPR_remaining > 1) { - BuildMI(BB, PPC32::OR, 2, GPR[GPR_idx]).addReg(ArgReg) + BuildMI(BB, PPC::OR, 2, GPR[GPR_idx]).addReg(ArgReg) .addReg(ArgReg); - BuildMI(BB, PPC32::OR, 2, GPR[GPR_idx+1]).addReg(ArgReg+1) + BuildMI(BB, PPC::OR, 2, GPR[GPR_idx+1]).addReg(ArgReg+1) .addReg(ArgReg+1); CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use); CallMI->addRegOperand(GPR[GPR_idx+1], MachineOperand::Use); } if (GPR_remaining <= 1 || isVarArg) { - BuildMI(BB, PPC32::STW, 3).addReg(ArgReg).addSImm(ArgOffset) - .addReg(PPC32::R1); - BuildMI(BB, PPC32::STW, 3).addReg(ArgReg+1).addSImm(ArgOffset+4) - .addReg(PPC32::R1); + BuildMI(BB, PPC::STW, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); + BuildMI(BB, PPC::STW, 3).addReg(ArgReg+1).addSImm(ArgOffset+4) + .addReg(PPC::R1); } ArgOffset += 4; // 8 byte entry, not 4. @@ -1521,7 +1521,7 @@ ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; // Reg or stack? if (FPR_remaining > 0) { - BuildMI(BB, PPC32::FMR, 1, FPR[FPR_idx]).addReg(ArgReg); + BuildMI(BB, PPC::FMR, 1, FPR[FPR_idx]).addReg(ArgReg); CallMI->addRegOperand(FPR[FPR_idx], MachineOperand::Use); FPR_remaining--; FPR_idx++; @@ -1529,47 +1529,47 @@ // If this is a vararg function, and there are GPRs left, also // pass the float in an int. Otherwise, put it on the stack. if (isVarArg) { - BuildMI(BB, PPC32::STFS, 3).addReg(ArgReg).addSImm(ArgOffset) - .addReg(PPC32::R1); + BuildMI(BB, PPC::STFS, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); if (GPR_remaining > 0) { - BuildMI(BB, PPC32::LWZ, 2, GPR[GPR_idx]) + BuildMI(BB, PPC::LWZ, 2, GPR[GPR_idx]) .addSImm(ArgOffset).addReg(ArgReg); CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use); } } } else { - BuildMI(BB, PPC32::STFS, 3).addReg(ArgReg).addSImm(ArgOffset) - .addReg(PPC32::R1); + BuildMI(BB, PPC::STFS, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); } break; case cFP64: ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; // Reg or stack? if (FPR_remaining > 0) { - BuildMI(BB, PPC32::FMR, 1, FPR[FPR_idx]).addReg(ArgReg); + BuildMI(BB, PPC::FMR, 1, FPR[FPR_idx]).addReg(ArgReg); CallMI->addRegOperand(FPR[FPR_idx], MachineOperand::Use); FPR_remaining--; FPR_idx++; // For vararg functions, must pass doubles via int regs as well if (isVarArg) { - BuildMI(BB, PPC32::STFD, 3).addReg(ArgReg).addSImm(ArgOffset) - .addReg(PPC32::R1); + BuildMI(BB, PPC::STFD, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); // Doubles can be split across reg + stack for varargs if (GPR_remaining > 0) { - BuildMI(BB, PPC32::LWZ, 2, GPR[GPR_idx]).addSImm(ArgOffset) - .addReg(PPC32::R1); + BuildMI(BB, PPC::LWZ, 2, GPR[GPR_idx]).addSImm(ArgOffset) + .addReg(PPC::R1); CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use); } if (GPR_remaining > 1) { - BuildMI(BB, PPC32::LWZ, 2, GPR[GPR_idx+1]) - .addSImm(ArgOffset+4).addReg(PPC32::R1); + BuildMI(BB, PPC::LWZ, 2, GPR[GPR_idx+1]) + .addSImm(ArgOffset+4).addReg(PPC::R1); CallMI->addRegOperand(GPR[GPR_idx+1], MachineOperand::Use); } } } else { - BuildMI(BB, PPC32::STFD, 3).addReg(ArgReg).addSImm(ArgOffset) - .addReg(PPC32::R1); + BuildMI(BB, PPC::STFD, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); } // Doubles use 8 bytes, and 2 GPRs worth of param space ArgOffset += 4; @@ -1584,14 +1584,14 @@ GPR_idx++; } } else { - BuildMI(BB, PPC32::ADJCALLSTACKDOWN, 1).addImm(0); + BuildMI(BB, PPC::ADJCALLSTACKDOWN, 1).addImm(0); } - BuildMI(BB, PPC32::IMPLICIT_DEF, 0, PPC32::LR); + BuildMI(BB, PPC::IMPLICIT_DEF, 0, PPC::LR); BB->push_back(CallMI); // These functions are automatically eliminated by the prolog/epilog pass - BuildMI(BB, PPC32::ADJCALLSTACKUP, 1).addImm(NumBytes); + BuildMI(BB, PPC::ADJCALLSTACKUP, 1).addImm(NumBytes); // If there is a return value, scavenge the result from the location the call // leaves it in... @@ -1603,15 +1603,15 @@ case cShort: case cInt: // Integral results are in r3 - BuildMI(BB, PPC32::OR, 2, Ret.Reg).addReg(PPC32::R3).addReg(PPC32::R3); + BuildMI(BB, PPC::OR, 2, Ret.Reg).addReg(PPC::R3).addReg(PPC::R3); break; case cFP32: // Floating-point return values live in f1 case cFP64: - BuildMI(BB, PPC32::FMR, 1, Ret.Reg).addReg(PPC32::F1); + BuildMI(BB, PPC::FMR, 1, Ret.Reg).addReg(PPC::F1); break; case cLong: // Long values are in r3:r4 - BuildMI(BB, PPC32::OR, 2, Ret.Reg).addReg(PPC32::R3).addReg(PPC32::R3); - BuildMI(BB, PPC32::OR, 2, Ret.Reg+1).addReg(PPC32::R4).addReg(PPC32::R4); + BuildMI(BB, PPC::OR, 2, Ret.Reg).addReg(PPC::R3).addReg(PPC::R3); + BuildMI(BB, PPC::OR, 2, Ret.Reg+1).addReg(PPC::R4).addReg(PPC::R4); break; default: assert(0 && "Unknown class!"); } @@ -1630,13 +1630,13 @@ return; } // Emit a CALL instruction with PC-relative displacement. - TheCall = BuildMI(PPC32::CALLpcrel, 1).addGlobalAddress(F, true); + TheCall = BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(F, true); // Add it to the set of functions called to be used by the Printer TM.CalledFunctions.insert(F); } else { // Emit an indirect call through the CTR unsigned Reg = getReg(CI.getCalledValue()); - BuildMI(BB, PPC32::MTCTR, 1).addReg(Reg); - TheCall = BuildMI(PPC32::CALLindirect, 2).addZImm(20).addZImm(0); + BuildMI(BB, PPC::MTCTR, 1).addReg(Reg); + TheCall = BuildMI(PPC::CALLindirect, 2).addZImm(20).addZImm(0); } std::vector Args; @@ -1734,14 +1734,14 @@ case Intrinsic::vastart: // Get the address of the first vararg value... TmpReg1 = getReg(CI); - addFrameReference(BuildMI(BB, PPC32::ADDI, 2, TmpReg1), VarArgsFrameIndex, + addFrameReference(BuildMI(BB, PPC::ADDI, 2, TmpReg1), VarArgsFrameIndex, 0, false); return; case Intrinsic::vacopy: TmpReg1 = getReg(CI); TmpReg2 = getReg(CI.getOperand(1)); - BuildMI(BB, PPC32::OR, 2, TmpReg1).addReg(TmpReg2).addReg(TmpReg2); + BuildMI(BB, PPC::OR, 2, TmpReg1).addReg(TmpReg2).addReg(TmpReg2); return; case Intrinsic::vaend: return; @@ -1751,21 +1751,21 @@ MachineFrameInfo *MFI = F->getFrameInfo(); unsigned NumBytes = MFI->getStackSize(); - BuildMI(BB, PPC32::LWZ, 2, TmpReg1).addSImm(NumBytes+8) - .addReg(PPC32::R1); + BuildMI(BB, PPC::LWZ, 2, TmpReg1).addSImm(NumBytes+8) + .addReg(PPC::R1); } else { // Values other than zero are not implemented yet. - BuildMI(BB, PPC32::LI, 1, TmpReg1).addSImm(0); + BuildMI(BB, PPC::LI, 1, TmpReg1).addSImm(0); } return; case Intrinsic::frameaddress: TmpReg1 = getReg(CI); if (cast(CI.getOperand(1))->isNullValue()) { - BuildMI(BB, PPC32::OR, 2, TmpReg1).addReg(PPC32::R1).addReg(PPC32::R1); + BuildMI(BB, PPC::OR, 2, TmpReg1).addReg(PPC::R1).addReg(PPC::R1); } else { // Values other than zero are not implemented yet. - BuildMI(BB, PPC32::LI, 1, TmpReg1).addSImm(0); + BuildMI(BB, PPC::LI, 1, TmpReg1).addSImm(0); } return; @@ -1777,9 +1777,9 @@ TmpReg1 = getReg(CI.getOperand(1)); emitUCOM(BB, BB->end(), TmpReg1, TmpReg1); TmpReg2 = makeAnotherReg(Type::IntTy); - BuildMI(BB, PPC32::MFCR, TmpReg2); + BuildMI(BB, PPC::MFCR, TmpReg2); TmpReg3 = getReg(CI); - BuildMI(BB, PPC32::RLWINM, 4, TmpReg3).addReg(TmpReg2).addImm(4).addImm(31).addImm(31); + BuildMI(BB, PPC::RLWINM, 4, TmpReg3).addReg(TmpReg2).addImm(4).addImm(31).addImm(31); return; #endif @@ -1816,8 +1816,8 @@ assert(Ty == Type::FloatTy || Ty == Type::DoubleTy && "Unknown FP type!"); static const unsigned OpcodeTab[][4] = { - { PPC32::FADDS, PPC32::FSUBS, PPC32::FMULS, PPC32::FDIVS }, // Float - { PPC32::FADD, PPC32::FSUB, PPC32::FMUL, PPC32::FDIV }, // Double + { PPC::FADDS, PPC::FSUBS, PPC::FMULS, PPC::FDIVS }, // Float + { PPC::FADD, PPC::FSUB, PPC::FMUL, PPC::FDIV }, // Double }; unsigned Opcode = OpcodeTab[Ty != Type::FloatTy][OperatorClass]; @@ -1832,7 +1832,7 @@ if (Op0C->isExactlyValue(-0.0) && OperatorClass == 1) { // -0.0 - X === -X unsigned op1Reg = getReg(Op1, BB, IP); - BuildMI(*BB, IP, PPC32::FNEG, 1, DestReg).addReg(op1Reg); + BuildMI(*BB, IP, PPC::FNEG, 1, DestReg).addReg(op1Reg); return; } else { // R1 = op CST, R2 --> R1 = opr R2, CST @@ -1844,8 +1844,8 @@ assert(Ty == Type::FloatTy || Ty == Type::DoubleTy && "Unknown FP type!"); static const unsigned OpcodeTab[][4] = { - { PPC32::FADDS, PPC32::FSUBS, PPC32::FMULS, PPC32::FDIVS }, // Float - { PPC32::FADD, PPC32::FSUB, PPC32::FMUL, PPC32::FDIV }, // Double + { PPC::FADDS, PPC::FSUBS, PPC::FMULS, PPC::FDIVS }, // Float + { PPC::FADD, PPC::FSUB, PPC::FMUL, PPC::FDIV }, // Double }; unsigned Opcode = OpcodeTab[Ty != Type::FloatTy][OperatorClass]; @@ -1857,7 +1857,7 @@ // General case. static const unsigned OpcodeTab[] = { - PPC32::FADD, PPC32::FSUB, PPC32::FMUL, PPC32::FDIV + PPC::FADD, PPC::FSUB, PPC::FMUL, PPC::FDIV }; unsigned Opcode = OpcodeTab[OperatorClass]; @@ -1881,21 +1881,21 @@ // Arithmetic and Bitwise operators static const unsigned OpcodeTab[] = { - PPC32::ADD, PPC32::SUB, PPC32::AND, PPC32::OR, PPC32::XOR + PPC::ADD, PPC::SUB, PPC::AND, PPC::OR, PPC::XOR }; static const unsigned ImmOpcodeTab[] = { - PPC32::ADDI, PPC32::SUBI, PPC32::ANDIo, PPC32::ORI, PPC32::XORI + PPC::ADDI, PPC::SUBI, PPC::ANDIo, PPC::ORI, PPC::XORI }; static const unsigned RImmOpcodeTab[] = { - PPC32::ADDI, PPC32::SUBFIC, PPC32::ANDIo, PPC32::ORI, PPC32::XORI + PPC::ADDI, PPC::SUBFIC, PPC::ANDIo, PPC::ORI, PPC::XORI }; // Otherwise, code generate the full operation with a constant. static const unsigned BottomTab[] = { - PPC32::ADDC, PPC32::SUBC, PPC32::AND, PPC32::OR, PPC32::XOR + PPC::ADDC, PPC::SUBC, PPC::AND, PPC::OR, PPC::XOR }; static const unsigned TopTab[] = { - PPC32::ADDE, PPC32::SUBFE, PPC32::AND, PPC32::OR, PPC32::XOR + PPC::ADDE, PPC::SUBFE, PPC::AND, PPC::OR, PPC::XOR }; if (Class == cFP32 || Class == cFP64) { @@ -1913,8 +1913,8 @@ unsigned Op0Reg = getReg(RHS, MBB, IP), Op1Reg = getReg(LHS, MBB, IP); unsigned TmpReg = makeAnotherReg(Type::IntTy); emitUCOM(MBB, IP, Op0Reg, Op1Reg); - BuildMI(*MBB, IP, PPC32::MFCR, TmpReg); - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg).addReg(TmpReg).addImm(4) + BuildMI(*MBB, IP, PPC::MFCR, TmpReg); + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(TmpReg).addImm(4) .addImm(31).addImm(31); return; } @@ -1928,11 +1928,11 @@ int imm = CI->getRawValue() & 0xFFFF; if (Class == cLong) { - BuildMI(*MBB, IP, PPC32::SUBFIC, 2, DestReg+1).addReg(Op1r+1) + BuildMI(*MBB, IP, PPC::SUBFIC, 2, DestReg+1).addReg(Op1r+1) .addSImm(imm); - BuildMI(*MBB, IP, PPC32::SUBFZE, 1, DestReg).addReg(Op1r); + BuildMI(*MBB, IP, PPC::SUBFZE, 1, DestReg).addReg(Op1r); } else { - BuildMI(*MBB, IP, PPC32::SUBFIC, 2, DestReg).addReg(Op1r).addSImm(imm); + BuildMI(*MBB, IP, PPC::SUBFIC, 2, DestReg).addReg(Op1r).addSImm(imm); } return; } @@ -1959,9 +1959,9 @@ // xor X, -1 -> not X if (OperatorClass == 4 && Op1C->isAllOnesValue()) { - BuildMI(*MBB, IP, PPC32::NOR, 2, DestReg).addReg(Op0r).addReg(Op0r); + BuildMI(*MBB, IP, PPC::NOR, 2, DestReg).addReg(Op0r).addReg(Op0r); if (Class == cLong) // Invert the low part too - BuildMI(*MBB, IP, PPC32::NOR, 2, DestReg+1).addReg(Op0r+1) + BuildMI(*MBB, IP, PPC::NOR, 2, DestReg+1).addReg(Op0r+1) .addReg(Op0r+1); return; } @@ -2040,12 +2040,12 @@ unsigned Tmp2 = makeAnotherReg(Type::IntTy); unsigned Tmp3 = makeAnotherReg(Type::IntTy); unsigned Tmp4 = makeAnotherReg(Type::IntTy); - BuildMI(*MBB, IP, PPC32::MULHWU, 2, Tmp1).addReg(Op0r+1).addReg(Op1r+1); - BuildMI(*MBB, IP, PPC32::MULLW, 2, DestReg+1).addReg(Op0r+1).addReg(Op1r+1); - BuildMI(*MBB, IP, PPC32::MULLW, 2, Tmp2).addReg(Op0r+1).addReg(Op1r); - BuildMI(*MBB, IP, PPC32::ADD, 2, Tmp3).addReg(Tmp1).addReg(Tmp2); - BuildMI(*MBB, IP, PPC32::MULLW, 2, Tmp4).addReg(Op0r).addReg(Op1r+1); - BuildMI(*MBB, IP, PPC32::ADD, 2, DestReg).addReg(Tmp3).addReg(Tmp4); + BuildMI(*MBB, IP, PPC::MULHWU, 2, Tmp1).addReg(Op0r+1).addReg(Op1r+1); + BuildMI(*MBB, IP, PPC::MULLW, 2, DestReg+1).addReg(Op0r+1).addReg(Op1r+1); + BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp2).addReg(Op0r+1).addReg(Op1r); + BuildMI(*MBB, IP, PPC::ADD, 2, Tmp3).addReg(Tmp1).addReg(Tmp2); + BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp4).addReg(Op0r).addReg(Op1r+1); + BuildMI(*MBB, IP, PPC::ADD, 2, DestReg).addReg(Tmp3).addReg(Tmp4); return; } @@ -2057,21 +2057,21 @@ unsigned Tmp3 = makeAnotherReg(Type::IntTy); unsigned Tmp4 = makeAnotherReg(Type::IntTy); if (Op1->getType()->isSigned()) - BuildMI(*MBB, IP, PPC32::SRAWI, 2, Tmp0).addReg(Op1r).addImm(31); + BuildMI(*MBB, IP, PPC::SRAWI, 2, Tmp0).addReg(Op1r).addImm(31); else - BuildMI(*MBB, IP, PPC32::LI, 2, Tmp0).addSImm(0); - BuildMI(*MBB, IP, PPC32::MULHWU, 2, Tmp1).addReg(Op0r+1).addReg(Op1r); - BuildMI(*MBB, IP, PPC32::MULLW, 2, DestReg+1).addReg(Op0r+1).addReg(Op1r); - BuildMI(*MBB, IP, PPC32::MULLW, 2, Tmp2).addReg(Op0r+1).addReg(Tmp0); - BuildMI(*MBB, IP, PPC32::ADD, 2, Tmp3).addReg(Tmp1).addReg(Tmp2); - BuildMI(*MBB, IP, PPC32::MULLW, 2, Tmp4).addReg(Op0r).addReg(Op1r); - BuildMI(*MBB, IP, PPC32::ADD, 2, DestReg).addReg(Tmp3).addReg(Tmp4); + BuildMI(*MBB, IP, PPC::LI, 2, Tmp0).addSImm(0); + BuildMI(*MBB, IP, PPC::MULHWU, 2, Tmp1).addReg(Op0r+1).addReg(Op1r); + BuildMI(*MBB, IP, PPC::MULLW, 2, DestReg+1).addReg(Op0r+1).addReg(Op1r); + BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp2).addReg(Op0r+1).addReg(Tmp0); + BuildMI(*MBB, IP, PPC::ADD, 2, Tmp3).addReg(Tmp1).addReg(Tmp2); + BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp4).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, PPC::ADD, 2, DestReg).addReg(Tmp3).addReg(Tmp4); return; } // 32 x 32 -> 32 if (Class0 <= cInt && Class1 <= cInt) { - BuildMI(*MBB, IP, PPC32::MULLW, 2, DestReg).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, PPC::MULLW, 2, DestReg).addReg(Op0r).addReg(Op1r); return; } @@ -2087,18 +2087,18 @@ // Mul op0, 0 ==> 0 if (CI->isNullValue()) { - BuildMI(*MBB, IP, PPC32::LI, 1, DestReg).addSImm(0); + BuildMI(*MBB, IP, PPC::LI, 1, DestReg).addSImm(0); if (Class == cLong) - BuildMI(*MBB, IP, PPC32::LI, 1, DestReg+1).addSImm(0); + BuildMI(*MBB, IP, PPC::LI, 1, DestReg+1).addSImm(0); return; } // Mul op0, 1 ==> op0 if (CI->equalsInt(1)) { unsigned Op0r = getReg(Op0, MBB, IP); - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(Op0r).addReg(Op0r); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(Op0r).addReg(Op0r); if (Class == cLong) - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg+1).addReg(Op0r+1).addReg(Op0r+1); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(Op0r+1).addReg(Op0r+1); return; } @@ -2114,7 +2114,7 @@ if (canUseAsImmediateForOpcode(CI, 0)) { unsigned Op0r = getReg(Op0, MBB, IP); unsigned imm = CI->getRawValue() & 0xFFFF; - BuildMI(*MBB, IP, PPC32::MULLI, 2, DestReg).addReg(Op0r).addSImm(imm); + BuildMI(*MBB, IP, PPC::MULLI, 2, DestReg).addReg(Op0r).addSImm(imm); return; } } @@ -2187,7 +2187,7 @@ unsigned Op0Reg = getReg(Op0, BB, IP); unsigned Op1Reg = getReg(Op1, BB, IP); MachineInstr *TheCall = - BuildMI(PPC32::CALLpcrel, 1).addGlobalAddress(fmodfFn, true); + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(fmodfFn, true); std::vector Args; Args.push_back(ValueRecord(Op0Reg, Type::FloatTy)); Args.push_back(ValueRecord(Op1Reg, Type::FloatTy)); @@ -2205,7 +2205,7 @@ unsigned Op0Reg = getReg(Op0, BB, IP); unsigned Op1Reg = getReg(Op1, BB, IP); MachineInstr *TheCall = - BuildMI(PPC32::CALLpcrel, 1).addGlobalAddress(fmodFn, true); + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(fmodFn, true); std::vector Args; Args.push_back(ValueRecord(Op0Reg, Type::DoubleTy)); Args.push_back(ValueRecord(Op1Reg, Type::DoubleTy)); @@ -2220,7 +2220,7 @@ unsigned Op1Reg = getReg(Op1, BB, IP); unsigned NameIdx = Ty->isUnsigned()*2 + isDiv; MachineInstr *TheCall = - BuildMI(PPC32::CALLpcrel, 1).addGlobalAddress(Funcs[NameIdx], true); + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(Funcs[NameIdx], true); std::vector Args; Args.push_back(ValueRecord(Op0Reg, Type::LongTy)); @@ -2242,13 +2242,13 @@ if (V == 1) { // X /s 1 => X unsigned Op0Reg = getReg(Op0, BB, IP); - BuildMI(*BB, IP, PPC32::OR, 2, ResultReg).addReg(Op0Reg).addReg(Op0Reg); + BuildMI(*BB, IP, PPC::OR, 2, ResultReg).addReg(Op0Reg).addReg(Op0Reg); return; } if (V == -1) { // X /s -1 => -X unsigned Op0Reg = getReg(Op0, BB, IP); - BuildMI(*BB, IP, PPC32::NEG, 1, ResultReg).addReg(Op0Reg); + BuildMI(*BB, IP, PPC::NEG, 1, ResultReg).addReg(Op0Reg); return; } @@ -2257,15 +2257,15 @@ unsigned Op0Reg = getReg(Op0, BB, IP); unsigned TmpReg = makeAnotherReg(Op0->getType()); - BuildMI(*BB, IP, PPC32::SRAWI, 2, TmpReg).addReg(Op0Reg).addImm(log2V); - BuildMI(*BB, IP, PPC32::ADDZE, 1, ResultReg).addReg(TmpReg); + BuildMI(*BB, IP, PPC::SRAWI, 2, TmpReg).addReg(Op0Reg).addImm(log2V); + BuildMI(*BB, IP, PPC::ADDZE, 1, ResultReg).addReg(TmpReg); return; } } unsigned Op0Reg = getReg(Op0, BB, IP); unsigned Op1Reg = getReg(Op1, BB, IP); - unsigned Opcode = Ty->isSigned() ? PPC32::DIVW : PPC32::DIVWU; + unsigned Opcode = Ty->isSigned() ? PPC::DIVW : PPC::DIVWU; if (isDiv) { BuildMI(*BB, IP, Opcode, 2, ResultReg).addReg(Op0Reg).addReg(Op1Reg); @@ -2274,8 +2274,8 @@ unsigned TmpReg2 = makeAnotherReg(Op0->getType()); BuildMI(*BB, IP, Opcode, 2, TmpReg1).addReg(Op0Reg).addReg(Op1Reg); - BuildMI(*BB, IP, PPC32::MULLW, 2, TmpReg2).addReg(TmpReg1).addReg(Op1Reg); - BuildMI(*BB, IP, PPC32::SUBF, 2, ResultReg).addReg(TmpReg2).addReg(Op0Reg); + BuildMI(*BB, IP, PPC::MULLW, 2, TmpReg2).addReg(TmpReg1).addReg(Op1Reg); + BuildMI(*BB, IP, PPC::SUBF, 2, ResultReg).addReg(TmpReg2).addReg(Op0Reg); } } @@ -2313,45 +2313,45 @@ if (Amount < 32) { if (isLeftShift) { // FIXME: RLWIMI is a use-and-def of DestReg+1, but that violates SSA - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) .addImm(Amount).addImm(0).addImm(31-Amount); - BuildMI(*MBB, IP, PPC32::RLWIMI, 5).addReg(DestReg).addReg(SrcReg+1) + BuildMI(*MBB, IP, PPC::RLWIMI, 5).addReg(DestReg).addReg(SrcReg+1) .addImm(Amount).addImm(32-Amount).addImm(31); - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg+1).addReg(SrcReg+1) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg+1).addReg(SrcReg+1) .addImm(Amount).addImm(0).addImm(31-Amount); } else { // FIXME: RLWIMI is a use-and-def of DestReg, but that violates SSA - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg+1).addReg(SrcReg+1) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg+1).addReg(SrcReg+1) .addImm(32-Amount).addImm(Amount).addImm(31); - BuildMI(*MBB, IP, PPC32::RLWIMI, 5).addReg(DestReg+1).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::RLWIMI, 5).addReg(DestReg+1).addReg(SrcReg) .addImm(32-Amount).addImm(0).addImm(Amount-1); - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) .addImm(32-Amount).addImm(Amount).addImm(31); } } else { // Shifting more than 32 bits Amount -= 32; if (isLeftShift) { if (Amount != 0) { - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg).addReg(SrcReg+1) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg+1) .addImm(Amount).addImm(0).addImm(31-Amount); } else { - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg+1) + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg+1) .addReg(SrcReg+1); } - BuildMI(*MBB, IP, PPC32::LI, 1, DestReg+1).addSImm(0); + BuildMI(*MBB, IP, PPC::LI, 1, DestReg+1).addSImm(0); } else { if (Amount != 0) { if (isSigned) - BuildMI(*MBB, IP, PPC32::SRAWI, 2, DestReg+1).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg+1).addReg(SrcReg) .addImm(Amount); else - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg+1).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg+1).addReg(SrcReg) .addImm(32-Amount).addImm(Amount).addImm(31); } else { - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg+1).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) .addReg(SrcReg); } - BuildMI(*MBB, IP,PPC32::LI, 1, DestReg).addSImm(0); + BuildMI(*MBB, IP,PPC::LI, 1, DestReg).addSImm(0); } } } else { @@ -2364,20 +2364,20 @@ unsigned ShiftAmountReg = getReg (ShiftAmount, MBB, IP); if (isLeftShift) { - BuildMI(*MBB, IP, PPC32::SUBFIC, 2, TmpReg1).addReg(ShiftAmountReg) + BuildMI(*MBB, IP, PPC::SUBFIC, 2, TmpReg1).addReg(ShiftAmountReg) .addSImm(32); - BuildMI(*MBB, IP, PPC32::SLW, 2, TmpReg2).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg2).addReg(SrcReg) .addReg(ShiftAmountReg); - BuildMI(*MBB, IP, PPC32::SRW, 2, TmpReg3).addReg(SrcReg+1) + BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg3).addReg(SrcReg+1) .addReg(TmpReg1); - BuildMI(*MBB, IP, PPC32::OR, 2,TmpReg4).addReg(TmpReg2).addReg(TmpReg3); - BuildMI(*MBB, IP, PPC32::ADDI, 2, TmpReg5).addReg(ShiftAmountReg) + BuildMI(*MBB, IP, PPC::OR, 2,TmpReg4).addReg(TmpReg2).addReg(TmpReg3); + BuildMI(*MBB, IP, PPC::ADDI, 2, TmpReg5).addReg(ShiftAmountReg) .addSImm(-32); - BuildMI(*MBB, IP, PPC32::SLW, 2, TmpReg6).addReg(SrcReg+1) + BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg6).addReg(SrcReg+1) .addReg(TmpReg5); - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(TmpReg4) + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(TmpReg4) .addReg(TmpReg6); - BuildMI(*MBB, IP, PPC32::SLW, 2, DestReg+1).addReg(SrcReg+1) + BuildMI(*MBB, IP, PPC::SLW, 2, DestReg+1).addReg(SrcReg+1) .addReg(ShiftAmountReg); } else { if (isSigned) { @@ -2386,21 +2386,21 @@ std::cerr << "ERROR: Unimplemented: signed right shift of long\n"; abort(); } else { - BuildMI(*MBB, IP, PPC32::SUBFIC, 2, TmpReg1).addReg(ShiftAmountReg) + BuildMI(*MBB, IP, PPC::SUBFIC, 2, TmpReg1).addReg(ShiftAmountReg) .addSImm(32); - BuildMI(*MBB, IP, PPC32::SRW, 2, TmpReg2).addReg(SrcReg+1) + BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg2).addReg(SrcReg+1) .addReg(ShiftAmountReg); - BuildMI(*MBB, IP, PPC32::SLW, 2, TmpReg3).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg3).addReg(SrcReg) .addReg(TmpReg1); - BuildMI(*MBB, IP, PPC32::OR, 2, TmpReg4).addReg(TmpReg2) + BuildMI(*MBB, IP, PPC::OR, 2, TmpReg4).addReg(TmpReg2) .addReg(TmpReg3); - BuildMI(*MBB, IP, PPC32::ADDI, 2, TmpReg5).addReg(ShiftAmountReg) + BuildMI(*MBB, IP, PPC::ADDI, 2, TmpReg5).addReg(ShiftAmountReg) .addSImm(-32); - BuildMI(*MBB, IP, PPC32::SRW, 2, TmpReg6).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg6).addReg(SrcReg) .addReg(TmpReg5); - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg+1).addReg(TmpReg4) + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(TmpReg4) .addReg(TmpReg6); - BuildMI(*MBB, IP, PPC32::SRW, 2, DestReg).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::SRW, 2, DestReg).addReg(SrcReg) .addReg(ShiftAmountReg); } } @@ -2414,13 +2414,13 @@ unsigned Amount = CUI->getValue(); if (isLeftShift) { - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) .addImm(Amount).addImm(0).addImm(31-Amount); } else { if (isSigned) { - BuildMI(*MBB, IP, PPC32::SRAWI,2,DestReg).addReg(SrcReg).addImm(Amount); + BuildMI(*MBB, IP, PPC::SRAWI,2,DestReg).addReg(SrcReg).addImm(Amount); } else { - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) .addImm(32-Amount).addImm(Amount).addImm(31); } } @@ -2428,10 +2428,10 @@ unsigned ShiftAmountReg = getReg (ShiftAmount, MBB, IP); if (isLeftShift) { - BuildMI(*MBB, IP, PPC32::SLW, 2, DestReg).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::SLW, 2, DestReg).addReg(SrcReg) .addReg(ShiftAmountReg); } else { - BuildMI(*MBB, IP, isSigned ? PPC32::SRAW : PPC32::SRW, 2, DestReg) + BuildMI(*MBB, IP, isSigned ? PPC::SRAW : PPC::SRW, 2, DestReg) .addReg(SrcReg).addReg(ShiftAmountReg); } } @@ -2445,13 +2445,13 @@ void ISel::visitLoadInst(LoadInst &I) { // Immediate opcodes, for reg+imm addressing static const unsigned ImmOpcodes[] = { - PPC32::LBZ, PPC32::LHZ, PPC32::LWZ, - PPC32::LFS, PPC32::LFD, PPC32::LWZ + PPC::LBZ, PPC::LHZ, PPC::LWZ, + PPC::LFS, PPC::LFD, PPC::LWZ }; // Indexed opcodes, for reg+reg addressing static const unsigned IdxOpcodes[] = { - PPC32::LBZX, PPC32::LHZX, PPC32::LWZX, - PPC32::LFSX, PPC32::LFDX, PPC32::LWZX + PPC::LBZX, PPC::LHZX, PPC::LWZX, + PPC::LFSX, PPC::LFDX, PPC::LWZX }; unsigned Class = getClassB(I.getType()); @@ -2460,8 +2460,8 @@ unsigned DestReg = getReg(I); Value *SourceAddr = I.getOperand(0); - if (Class == cShort && I.getType()->isSigned()) ImmOpcode = PPC32::LHA; - if (Class == cShort && I.getType()->isSigned()) IdxOpcode = PPC32::LHAX; + if (Class == cShort && I.getType()->isSigned()) ImmOpcode = PPC::LHA; + if (Class == cShort && I.getType()->isSigned()) IdxOpcode = PPC::LHAX; if (AllocaInst *AI = dyn_castFixedAlloca(SourceAddr)) { unsigned FI = getFixedSizedAllocaFI(AI); @@ -2471,7 +2471,7 @@ } else if (Class == cByte && I.getType()->isSigned()) { unsigned TmpReg = makeAnotherReg(I.getType()); addFrameReference(BuildMI(BB, ImmOpcode, 2, TmpReg), FI); - BuildMI(BB, PPC32::EXTSB, 1, DestReg).addReg(TmpReg); + BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg); } else { addFrameReference(BuildMI(BB, ImmOpcode, 2, DestReg), FI); } @@ -2498,7 +2498,7 @@ unsigned TmpReg = makeAnotherReg(I.getType()); BuildMI(BB, ImmOpcode, 2, TmpReg).addSImm(offset->getValue()) .addReg(baseReg); - BuildMI(BB, PPC32::EXTSB, 1, DestReg).addReg(TmpReg); + BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg); } else { BuildMI(BB, ImmOpcode, 2, DestReg).addSImm(offset->getValue()) .addReg(baseReg); @@ -2510,13 +2510,13 @@ if (Class == cLong) { unsigned indexPlus4 = makeAnotherReg(Type::IntTy); - BuildMI(BB, PPC32::ADDI, 2, indexPlus4).addReg(indexReg).addSImm(4); + BuildMI(BB, PPC::ADDI, 2, indexPlus4).addReg(indexReg).addSImm(4); BuildMI(BB, IdxOpcode, 2, DestReg).addReg(indexReg).addReg(baseReg); BuildMI(BB, IdxOpcode, 2, DestReg+1).addReg(indexPlus4).addReg(baseReg); } else if (Class == cByte && I.getType()->isSigned()) { unsigned TmpReg = makeAnotherReg(I.getType()); BuildMI(BB, IdxOpcode, 2, TmpReg).addReg(indexReg).addReg(baseReg); - BuildMI(BB, PPC32::EXTSB, 1, DestReg).addReg(TmpReg); + BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg); } else { BuildMI(BB, IdxOpcode, 2, DestReg).addReg(indexReg).addReg(baseReg); } @@ -2533,7 +2533,7 @@ } else if (Class == cByte && I.getType()->isSigned()) { unsigned TmpReg = makeAnotherReg(I.getType()); BuildMI(BB, ImmOpcode, 2, TmpReg).addSImm(0).addReg(SrcAddrReg); - BuildMI(BB, PPC32::EXTSB, 1, DestReg).addReg(TmpReg); + BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg); } else { BuildMI(BB, ImmOpcode, 2, DestReg).addSImm(0).addReg(SrcAddrReg); } @@ -2544,13 +2544,13 @@ void ISel::visitStoreInst(StoreInst &I) { // Immediate opcodes, for reg+imm addressing static const unsigned ImmOpcodes[] = { - PPC32::STB, PPC32::STH, PPC32::STW, - PPC32::STFS, PPC32::STFD, PPC32::STW + PPC::STB, PPC::STH, PPC::STW, + PPC::STFS, PPC::STFD, PPC::STW }; // Indexed opcodes, for reg+reg addressing static const unsigned IdxOpcodes[] = { - PPC32::STBX, PPC32::STHX, PPC32::STWX, - PPC32::STFSX, PPC32::STFDX, PPC32::STWX + PPC::STBX, PPC::STHX, PPC::STWX, + PPC::STFSX, PPC::STFDX, PPC::STWX }; Value *SourceAddr = I.getOperand(1); @@ -2585,7 +2585,7 @@ if (Class == cLong) { unsigned indexPlus4 = makeAnotherReg(Type::IntTy); - BuildMI(BB, PPC32::ADDI, 2, indexPlus4).addReg(indexReg).addSImm(4); + BuildMI(BB, PPC::ADDI, 2, indexPlus4).addReg(indexReg).addSImm(4); BuildMI(BB, IdxOpcode, 3).addReg(ValReg).addReg(indexReg).addReg(baseReg); BuildMI(BB, IdxOpcode, 3).addReg(ValReg+1).addReg(indexPlus4) .addReg(baseReg); @@ -2656,16 +2656,16 @@ case cShort: case cInt: { unsigned TmpReg = makeAnotherReg(Type::IntTy); - BuildMI(*MBB, IP, PPC32::ADDIC, 2, TmpReg).addReg(SrcReg).addSImm(-1); - BuildMI(*MBB, IP, PPC32::SUBFE, 2, DestReg).addReg(TmpReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::ADDIC, 2, TmpReg).addReg(SrcReg).addSImm(-1); + BuildMI(*MBB, IP, PPC::SUBFE, 2, DestReg).addReg(TmpReg).addReg(SrcReg); break; } case cLong: { unsigned TmpReg = makeAnotherReg(Type::IntTy); unsigned SrcReg2 = makeAnotherReg(Type::IntTy); - BuildMI(*MBB, IP, PPC32::OR, 2, SrcReg2).addReg(SrcReg).addReg(SrcReg+1); - BuildMI(*MBB, IP, PPC32::ADDIC, 2, TmpReg).addReg(SrcReg2).addSImm(-1); - BuildMI(*MBB, IP, PPC32::SUBFE, 2, DestReg).addReg(TmpReg) + BuildMI(*MBB, IP, PPC::OR, 2, SrcReg2).addReg(SrcReg).addReg(SrcReg+1); + BuildMI(*MBB, IP, PPC::ADDIC, 2, TmpReg).addReg(SrcReg2).addSImm(-1); + BuildMI(*MBB, IP, PPC::SUBFE, 2, DestReg).addReg(TmpReg) .addReg(SrcReg2); break; } @@ -2680,13 +2680,13 @@ // Handle cast of Float -> Double if (SrcClass == cFP32 && DestClass == cFP64) { - BuildMI(*MBB, IP, PPC32::FMR, 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::FMR, 1, DestReg).addReg(SrcReg); return; } // Handle cast of Double -> Float if (SrcClass == cFP64 && DestClass == cFP32) { - BuildMI(*MBB, IP, PPC32::FRSP, 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::FRSP, 1, DestReg).addReg(SrcReg); return; } @@ -2699,7 +2699,7 @@ Args.push_back(ValueRecord(SrcReg, SrcTy)); Function *floatFn = (DestClass == cFP32) ? __floatdisfFn : __floatdidfFn; MachineInstr *TheCall = - BuildMI(PPC32::CALLpcrel, 1).addGlobalAddress(floatFn, true); + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(floatFn, true); doCall(ValueRecord(DestReg, DestTy), TheCall, Args, false); TM.CalledFunctions.insert(floatFn); return; @@ -2724,37 +2724,37 @@ unsigned TempF = makeAnotherReg(Type::DoubleTy); if (!SrcTy->isSigned()) { - BuildMI(*BB, IP, PPC32::LIS, 1, constantHi).addSImm(0x4330); - BuildMI(*BB, IP, PPC32::LI, 1, constantLo).addSImm(0); - addFrameReference(BuildMI(*BB, IP, PPC32::STW, 3).addReg(constantHi), + BuildMI(*BB, IP, PPC::LIS, 1, constantHi).addSImm(0x4330); + BuildMI(*BB, IP, PPC::LI, 1, constantLo).addSImm(0); + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(constantHi), ConstantFrameIndex); - addFrameReference(BuildMI(*BB, IP, PPC32::STW, 3).addReg(constantLo), + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(constantLo), ConstantFrameIndex, 4); - addFrameReference(BuildMI(*BB, IP, PPC32::STW, 3).addReg(constantHi), + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(constantHi), ValueFrameIdx); - addFrameReference(BuildMI(*BB, IP, PPC32::STW, 3).addReg(SrcReg), + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(SrcReg), ValueFrameIdx, 4); - addFrameReference(BuildMI(*BB, IP, PPC32::LFD, 2, ConstF), + addFrameReference(BuildMI(*BB, IP, PPC::LFD, 2, ConstF), ConstantFrameIndex); - addFrameReference(BuildMI(*BB, IP, PPC32::LFD, 2, TempF), ValueFrameIdx); - BuildMI(*BB, IP, PPC32::FSUB, 2, DestReg).addReg(TempF).addReg(ConstF); + addFrameReference(BuildMI(*BB, IP, PPC::LFD, 2, TempF), ValueFrameIdx); + BuildMI(*BB, IP, PPC::FSUB, 2, DestReg).addReg(TempF).addReg(ConstF); } else { unsigned TempLo = makeAnotherReg(Type::IntTy); - BuildMI(*BB, IP, PPC32::LIS, 1, constantHi).addSImm(0x4330); - BuildMI(*BB, IP, PPC32::LIS, 1, constantLo).addSImm(0x8000); - addFrameReference(BuildMI(*BB, IP, PPC32::STW, 3).addReg(constantHi), + BuildMI(*BB, IP, PPC::LIS, 1, constantHi).addSImm(0x4330); + BuildMI(*BB, IP, PPC::LIS, 1, constantLo).addSImm(0x8000); + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(constantHi), ConstantFrameIndex); - addFrameReference(BuildMI(*BB, IP, PPC32::STW, 3).addReg(constantLo), + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(constantLo), ConstantFrameIndex, 4); - addFrameReference(BuildMI(*BB, IP, PPC32::STW, 3).addReg(constantHi), + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(constantHi), ValueFrameIdx); - BuildMI(*BB, IP, PPC32::XORIS, 2, TempLo).addReg(SrcReg).addImm(0x8000); - addFrameReference(BuildMI(*BB, IP, PPC32::STW, 3).addReg(TempLo), + BuildMI(*BB, IP, PPC::XORIS, 2, TempLo).addReg(SrcReg).addImm(0x8000); + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(TempLo), ValueFrameIdx, 4); - addFrameReference(BuildMI(*BB, IP, PPC32::LFD, 2, ConstF), + addFrameReference(BuildMI(*BB, IP, PPC::LFD, 2, ConstF), ConstantFrameIndex); - addFrameReference(BuildMI(*BB, IP, PPC32::LFD, 2, TempF), ValueFrameIdx); - BuildMI(*BB, IP, PPC32::FSUB, 2, DestReg).addReg(TempF).addReg(ConstF); + addFrameReference(BuildMI(*BB, IP, PPC::LFD, 2, TempF), ValueFrameIdx); + BuildMI(*BB, IP, PPC::FSUB, 2, DestReg).addReg(TempF).addReg(ConstF); } return; } @@ -2771,7 +2771,7 @@ Args.push_back(ValueRecord(SrcReg, SrcTy)); Function *floatFn = Funcs[nameIndex]; MachineInstr *TheCall = - BuildMI(PPC32::CALLpcrel, 1).addGlobalAddress(floatFn, true); + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(floatFn, true); doCall(ValueRecord(DestReg, DestTy), TheCall, Args, false); TM.CalledFunctions.insert(floatFn); return; @@ -2784,8 +2784,8 @@ unsigned TempReg = makeAnotherReg(Type::DoubleTy); // Convert to integer in the FP reg and store it to a stack slot - BuildMI(*BB, IP, PPC32::FCTIWZ, 1, TempReg).addReg(SrcReg); - addFrameReference(BuildMI(*BB, IP, PPC32::STFD, 3) + BuildMI(*BB, IP, PPC::FCTIWZ, 1, TempReg).addReg(SrcReg); + addFrameReference(BuildMI(*BB, IP, PPC::STFD, 3) .addReg(TempReg), ValueFrameIdx); // There is no load signed byte opcode, so we must emit a sign extend for @@ -2793,12 +2793,12 @@ // correct offset. if (DestClass == cByte) { unsigned TempReg2 = makeAnotherReg(DestTy); - addFrameReference(BuildMI(*BB, IP, PPC32::LBZ, 2, TempReg2), + addFrameReference(BuildMI(*BB, IP, PPC::LBZ, 2, TempReg2), ValueFrameIdx, 7); - BuildMI(*MBB, IP, PPC32::EXTSB, DestReg).addReg(TempReg2); + BuildMI(*MBB, IP, PPC::EXTSB, DestReg).addReg(TempReg2); } else { int offset = (DestClass == cShort) ? 6 : 4; - unsigned LoadOp = (DestClass == cShort) ? PPC32::LHA : PPC32::LWZ; + unsigned LoadOp = (DestClass == cShort) ? PPC::LHA : PPC::LWZ; addFrameReference(BuildMI(*BB, IP, LoadOp, 2, DestReg), ValueFrameIdx, offset); } @@ -2830,45 +2830,45 @@ // Convert from floating point to unsigned 32-bit value // Use 0 if incoming value is < 0.0 - BuildMI(*BB, IP, PPC32::FSEL, 3, UseZero).addReg(SrcReg).addReg(SrcReg) + BuildMI(*BB, IP, PPC::FSEL, 3, UseZero).addReg(SrcReg).addReg(SrcReg) .addReg(Zero); // Use 2**32 - 1 if incoming value is >= 2**32 - BuildMI(*BB, IP, PPC32::FSUB, 2, UseMaxInt).addReg(MaxInt).addReg(SrcReg); - BuildMI(*BB, IP, PPC32::FSEL, 3, UseChoice).addReg(UseMaxInt) + BuildMI(*BB, IP, PPC::FSUB, 2, UseMaxInt).addReg(MaxInt).addReg(SrcReg); + BuildMI(*BB, IP, PPC::FSEL, 3, UseChoice).addReg(UseMaxInt) .addReg(UseZero).addReg(MaxInt); // Subtract 2**31 - BuildMI(*BB, IP, PPC32::FSUB, 2, TmpReg).addReg(UseChoice).addReg(Border); + BuildMI(*BB, IP, PPC::FSUB, 2, TmpReg).addReg(UseChoice).addReg(Border); // Use difference if >= 2**31 - BuildMI(*BB, IP, PPC32::FCMPU, 2, PPC32::CR0).addReg(UseChoice) + BuildMI(*BB, IP, PPC::FCMPU, 2, PPC::CR0).addReg(UseChoice) .addReg(Border); - BuildMI(*BB, IP, PPC32::FSEL, 3, TmpReg2).addReg(TmpReg).addReg(TmpReg) + BuildMI(*BB, IP, PPC::FSEL, 3, TmpReg2).addReg(TmpReg).addReg(TmpReg) .addReg(UseChoice); // Convert to integer - BuildMI(*BB, IP, PPC32::FCTIWZ, 1, ConvReg).addReg(TmpReg2); - addFrameReference(BuildMI(*BB, IP, PPC32::STFD, 3).addReg(ConvReg), + BuildMI(*BB, IP, PPC::FCTIWZ, 1, ConvReg).addReg(TmpReg2); + addFrameReference(BuildMI(*BB, IP, PPC::STFD, 3).addReg(ConvReg), FrameIdx); if (DestClass == cByte) { - addFrameReference(BuildMI(*BB, IP, PPC32::LBZ, 2, DestReg), + addFrameReference(BuildMI(*BB, IP, PPC::LBZ, 2, DestReg), FrameIdx, 7); } else if (DestClass == cShort) { - addFrameReference(BuildMI(*BB, IP, PPC32::LHZ, 2, DestReg), + addFrameReference(BuildMI(*BB, IP, PPC::LHZ, 2, DestReg), FrameIdx, 6); } if (DestClass == cInt) { - addFrameReference(BuildMI(*BB, IP, PPC32::LWZ, 2, IntTmp), + addFrameReference(BuildMI(*BB, IP, PPC::LWZ, 2, IntTmp), FrameIdx, 4); - BuildMI(*BB, IP, PPC32::BLT, 2).addReg(PPC32::CR0).addMBB(PhiMBB); - BuildMI(*BB, IP, PPC32::B, 1).addMBB(XorMBB); + BuildMI(*BB, IP, PPC::BLT, 2).addReg(PPC::CR0).addMBB(PhiMBB); + BuildMI(*BB, IP, PPC::B, 1).addMBB(XorMBB); // XorMBB: // add 2**31 if input was >= 2**31 BB = XorMBB; - BuildMI(BB, PPC32::XORIS, 2, XorReg).addReg(IntTmp).addImm(0x8000); + BuildMI(BB, PPC::XORIS, 2, XorReg).addReg(IntTmp).addImm(0x8000); XorMBB->addSuccessor(PhiMBB); // PhiMBB: // DestReg = phi [ IntTmp, OldMBB ], [ XorReg, XorMBB ] BB = PhiMBB; - BuildMI(BB, PPC32::PHI, 2, DestReg).addReg(IntTmp).addMBB(OldMBB) + BuildMI(BB, PPC::PHI, 2, DestReg).addReg(IntTmp).addMBB(OldMBB) .addReg(XorReg).addMBB(XorMBB); } } @@ -2889,12 +2889,12 @@ // handle long dest class now to keep switch clean if (DestClass == cLong) { if (SrcClass == cLong) { - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg+1).addReg(SrcReg+1) + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg+1) .addReg(SrcReg+1); } else { - BuildMI(*MBB, IP, PPC32::LI, 1, DestReg).addSImm(0); - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg+1).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::LI, 1, DestReg).addSImm(0); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) .addReg(SrcReg); } return; @@ -2906,9 +2906,9 @@ case cByte: case cShort: if (SrcClass == DestClass) - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); else - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) .addImm(0).addImm(clearBits).addImm(31); break; case cLong: @@ -2916,9 +2916,9 @@ // Fall through case cInt: if (DestClass == cInt) - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); else - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) .addImm(0).addImm(clearBits).addImm(31); break; } @@ -2930,12 +2930,12 @@ // handle long dest class now to keep switch clean if (DestClass == cLong) { if (SrcClass == cLong) { - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg+1).addReg(SrcReg+1) + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg+1) .addReg(SrcReg+1); } else { - BuildMI(*MBB, IP, PPC32::SRAWI, 2, DestReg).addReg(SrcReg).addImm(31); - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg+1).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg).addReg(SrcReg).addImm(31); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) .addReg(SrcReg); } return; @@ -2945,28 +2945,28 @@ switch (SrcClass) { case cByte: if (DestClass == cByte) - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); else - BuildMI(*MBB, IP, PPC32::EXTSB, 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg); break; case cShort: if (DestClass == cByte) - BuildMI(*MBB, IP, PPC32::EXTSB, 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg); else if (DestClass == cShort) - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); else - BuildMI(*MBB, IP, PPC32::EXTSH, 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::EXTSH, 1, DestReg).addReg(SrcReg); break; case cLong: ++SrcReg; // Fall through case cInt: if (DestClass == cByte) - BuildMI(*MBB, IP, PPC32::EXTSB, 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg); else if (DestClass == cShort) - BuildMI(*MBB, IP, PPC32::EXTSH, 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::EXTSH, 1, DestReg).addReg(SrcReg); else - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); break; } return; @@ -2977,12 +2977,12 @@ // handle long dest class now to keep switch clean if (DestClass == cLong) { if (SrcClass == cLong) { - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg+1).addReg(SrcReg+1). + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg+1). addReg(SrcReg+1); } else { - BuildMI(*MBB, IP, PPC32::LI, 1, DestReg).addSImm(0); - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg+1).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::LI, 1, DestReg).addSImm(0); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) .addReg(SrcReg); } return; @@ -2993,19 +2993,19 @@ case cByte: if (DestClass == cByte) // uByte 255 -> signed byte == -1 - BuildMI(*MBB, IP, PPC32::EXTSB, 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg); else // uByte 255 -> signed short/int == 255 - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg).addReg(SrcReg).addImm(0) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg).addImm(0) .addImm(24).addImm(31); break; case cShort: if (DestClass == cByte) - BuildMI(*MBB, IP, PPC32::EXTSB, 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg); else if (DestClass == cShort) - BuildMI(*MBB, IP, PPC32::EXTSH, 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::EXTSH, 1, DestReg).addReg(SrcReg); else - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg).addReg(SrcReg).addImm(0) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg).addImm(0) .addImm(16).addImm(31); break; case cLong: @@ -3013,11 +3013,11 @@ // Fall through case cInt: if (DestClass == cByte) - BuildMI(*MBB, IP, PPC32::EXTSB, 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg); else if (DestClass == cShort) - BuildMI(*MBB, IP, PPC32::EXTSH, 1, DestReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::EXTSH, 1, DestReg).addReg(SrcReg); else - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); break; } return; @@ -3028,12 +3028,12 @@ // handle long dest class now to keep switch clean if (DestClass == cLong) { if (SrcClass == cLong) { - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg+1).addReg(SrcReg+1) + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg+1) .addReg(SrcReg+1); } else { - BuildMI(*MBB, IP, PPC32::SRAWI, 2, DestReg).addReg(SrcReg).addImm(31); - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg+1).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg).addReg(SrcReg).addImm(31); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) .addReg(SrcReg); } return; @@ -3046,20 +3046,20 @@ case cShort: if (DestClass == cByte || DestClass == cShort) // sbyte -1 -> ubyte 0x000000FF - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) .addImm(0).addImm(clearBits).addImm(31); else // sbyte -1 -> ubyte 0xFFFFFFFF - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); break; case cLong: ++SrcReg; // Fall through case cInt: if (DestClass == cInt) - BuildMI(*MBB, IP, PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); else - BuildMI(*MBB, IP, PPC32::RLWINM, 4, DestReg).addReg(SrcReg) + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) .addImm(0).addImm(clearBits).addImm(31); break; } @@ -3097,7 +3097,7 @@ } // Increment the VAList pointer... - BuildMI(BB, PPC32::ADDI, 2, DestReg).addReg(VAList).addSImm(Size); + BuildMI(BB, PPC::ADDI, 2, DestReg).addReg(VAList).addSImm(Size); } void ISel::visitVAArgInst(VAArgInst &I) { @@ -3112,18 +3112,18 @@ case Type::PointerTyID: case Type::UIntTyID: case Type::IntTyID: - BuildMI(BB, PPC32::LWZ, 2, DestReg).addSImm(0).addReg(VAList); + BuildMI(BB, PPC::LWZ, 2, DestReg).addSImm(0).addReg(VAList); break; case Type::ULongTyID: case Type::LongTyID: - BuildMI(BB, PPC32::LWZ, 2, DestReg).addSImm(0).addReg(VAList); - BuildMI(BB, PPC32::LWZ, 2, DestReg+1).addSImm(4).addReg(VAList); + BuildMI(BB, PPC::LWZ, 2, DestReg).addSImm(0).addReg(VAList); + BuildMI(BB, PPC::LWZ, 2, DestReg+1).addSImm(4).addReg(VAList); break; case Type::FloatTyID: - BuildMI(BB, PPC32::LFS, 2, DestReg).addSImm(0).addReg(VAList); + BuildMI(BB, PPC::LFS, 2, DestReg).addSImm(0).addReg(VAList); break; case Type::DoubleTyID: - BuildMI(BB, PPC32::LFD, 2, DestReg).addSImm(0).addReg(VAList); + BuildMI(BB, PPC::LFD, 2, DestReg).addSImm(0).addReg(VAList); break; } } @@ -3228,7 +3228,7 @@ // that the base reg is updated appropriately. if (pendingAdd) { assert(pendingAddReg != 0 && "Uninitialized register in pending add!"); - BuildMI(*MBB, IP, PPC32::ADD, 2, nextBasePtrReg).addReg(basePtrReg) + BuildMI(*MBB, IP, PPC::ADD, 2, nextBasePtrReg).addReg(basePtrReg) .addReg(pendingAddReg); basePtrReg = nextBasePtrReg; nextBasePtrReg = makeAnotherReg(Type::IntTy); @@ -3245,14 +3245,14 @@ } else { // Try and generate an immediate addition if possible if (cgo.size->isNullValue()) { - BuildMI(*MBB, IP, PPC32::OR, 2, nextBasePtrReg).addReg(basePtrReg) + BuildMI(*MBB, IP, PPC::OR, 2, nextBasePtrReg).addReg(basePtrReg) .addReg(basePtrReg); } else if (canUseAsImmediateForOpcode(cgo.size, 0)) { - BuildMI(*MBB, IP, PPC32::ADDI, 2, nextBasePtrReg).addReg(basePtrReg) + BuildMI(*MBB, IP, PPC::ADDI, 2, nextBasePtrReg).addReg(basePtrReg) .addSImm(cgo.size->getValue()); } else { unsigned Op1r = getReg(cgo.size, MBB, IP); - BuildMI(*MBB, IP, PPC32::ADD, 2, nextBasePtrReg).addReg(basePtrReg) + BuildMI(*MBB, IP, PPC::ADD, 2, nextBasePtrReg).addReg(basePtrReg) .addReg(Op1r); } } @@ -3276,12 +3276,12 @@ if (pendingAdd) { unsigned nextBasePtrReg = makeAnotherReg(Type::IntTy); assert(pendingAddReg != 0 && "Uninitialized register in pending add!"); - BuildMI(*MBB, IP, PPC32::ADD, 2, nextBasePtrReg).addReg(basePtrReg) + BuildMI(*MBB, IP, PPC::ADD, 2, nextBasePtrReg).addReg(basePtrReg) .addReg(pendingAddReg); basePtrReg = nextBasePtrReg; } } - BuildMI (*MBB, IP, PPC32::OR, 2, TargetReg).addReg(basePtrReg) + BuildMI (*MBB, IP, PPC::OR, 2, TargetReg).addReg(basePtrReg) .addReg(basePtrReg); *RemainderPtr = remainder; return; @@ -3290,7 +3290,7 @@ // If we still have a pending add at this point, emit it now if (pendingAdd) { unsigned TmpReg = makeAnotherReg(Type::IntTy); - BuildMI(*MBB, IP, PPC32::ADD, 2, TmpReg).addReg(pendingAddReg) + BuildMI(*MBB, IP, PPC::ADD, 2, TmpReg).addReg(pendingAddReg) .addReg(basePtrReg); basePtrReg = TmpReg; } @@ -3299,14 +3299,14 @@ // basePtrReg. Move it to the register where we were expected to // put the answer. if (remainder->isNullValue()) { - BuildMI (*MBB, IP, PPC32::OR, 2, TargetReg).addReg(basePtrReg) + BuildMI (*MBB, IP, PPC::OR, 2, TargetReg).addReg(basePtrReg) .addReg(basePtrReg); } else if (canUseAsImmediateForOpcode(remainder, 0)) { - BuildMI(*MBB, IP, PPC32::ADDI, 2, TargetReg).addReg(basePtrReg) + BuildMI(*MBB, IP, PPC::ADDI, 2, TargetReg).addReg(basePtrReg) .addSImm(remainder->getValue()); } else { unsigned Op1r = getReg(remainder, MBB, IP); - BuildMI(*MBB, IP, PPC32::ADD, 2, TargetReg).addReg(basePtrReg).addReg(Op1r); + BuildMI(*MBB, IP, PPC::ADD, 2, TargetReg).addReg(basePtrReg).addReg(Op1r); } } @@ -3334,19 +3334,19 @@ // AddedSize = add , 15 unsigned AddedSizeReg = makeAnotherReg(Type::UIntTy); - BuildMI(BB, PPC32::ADDI, 2, AddedSizeReg).addReg(TotalSizeReg).addSImm(15); + BuildMI(BB, PPC::ADDI, 2, AddedSizeReg).addReg(TotalSizeReg).addSImm(15); // AlignedSize = and , ~15 unsigned AlignedSize = makeAnotherReg(Type::UIntTy); - BuildMI(BB, PPC32::RLWINM, 4, AlignedSize).addReg(AddedSizeReg).addImm(0) + BuildMI(BB, PPC::RLWINM, 4, AlignedSize).addReg(AddedSizeReg).addImm(0) .addImm(0).addImm(27); // Subtract size from stack pointer, thereby allocating some space. - BuildMI(BB, PPC32::SUB, 2, PPC32::R1).addReg(PPC32::R1).addReg(AlignedSize); + BuildMI(BB, PPC::SUB, 2, PPC::R1).addReg(PPC::R1).addReg(AlignedSize); // Put a pointer to the space into the result register, by copying // the stack pointer. - BuildMI(BB, PPC32::OR, 2, getReg(I)).addReg(PPC32::R1).addReg(PPC32::R1); + BuildMI(BB, PPC::OR, 2, getReg(I)).addReg(PPC::R1).addReg(PPC::R1); // Inform the Frame Information that we have just allocated a variable-sized // object. @@ -3372,7 +3372,7 @@ std::vector Args; Args.push_back(ValueRecord(Arg, Type::UIntTy)); MachineInstr *TheCall = - BuildMI(PPC32::CALLpcrel, 1).addGlobalAddress(mallocFn, true); + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(mallocFn, true); doCall(ValueRecord(getReg(I), I.getType()), TheCall, Args, false); TM.CalledFunctions.insert(mallocFn); } @@ -3385,12 +3385,12 @@ std::vector Args; Args.push_back(ValueRecord(I.getOperand(0))); MachineInstr *TheCall = - BuildMI(PPC32::CALLpcrel, 1).addGlobalAddress(freeFn, true); + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(freeFn, true); doCall(ValueRecord(0, Type::VoidTy), TheCall, Args, false); TM.CalledFunctions.insert(freeFn); } -/// createPPC32SimpleInstructionSelector - This pass converts an LLVM function +/// createPPCSimpleInstructionSelector - This pass converts an LLVM function /// into a machine code representation is a very simple peep-hole fashion. The /// generated code sucks but the implementation is nice and simple. /// Index: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.8 llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.9 --- llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.8 Tue Aug 10 14:03:31 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Tue Aug 10 17:47:03 2004 @@ -42,7 +42,7 @@ // // PowerPC instruction formats -class PPC32I opcode, bit ppc64, bit vmx> : Instruction { +class I opcode, bit ppc64, bit vmx> : Instruction { field bits<32> Inst; bits<3> ArgCount; @@ -55,13 +55,13 @@ bit VMX = vmx; let Name = name; - let Namespace = "PPC32"; + let Namespace = "PPC"; let Inst{0-5} = opcode; } // 1.7.1 I-Form class IForm opcode, bit aa, bit lk, bit ppc64, bit vmx> - : PPC32I { + : I { field bits<24> LI; let ArgCount = 1; @@ -78,7 +78,7 @@ // 1.7.2 B-Form class BForm opcode, bit aa, bit lk, bit ppc64, bit vmx> - : PPC32I { + : I { field bits<5> BO; field bits<5> BI; field bits<14> BD; @@ -110,7 +110,7 @@ // 1.7.4 D-Form class DForm_base opcode, bit ppc64, bit vmx> - : PPC32I { + : I { field bits<5> A; field bits<5> B; field bits<16> C; @@ -162,7 +162,7 @@ } class DForm_5 opcode, bit ppc64, bit vmx> - : PPC32I { + : I { field bits<3> BF; field bits<1> L; field bits<5> RA; @@ -224,7 +224,7 @@ // 1.7.6 X-Form class XForm_base_r3xo opcode, bits<10> xo, bit rc, - bit ppc64, bit vmx> : PPC32I { + bit ppc64, bit vmx> : I { let ArgCount = 3; field bits<5> ST; field bits<5> A; @@ -278,7 +278,7 @@ } class XForm_16 opcode, bits<10> xo, bit ppc64, bit vmx> - : PPC32I { + : I { field bits<3> BF; field bits<1> L; field bits<5> RA; @@ -306,7 +306,7 @@ } class XForm_17 opcode, bits<10> xo, bit ppc64, bit vmx> - : PPC32I { + : I { field bits<3> BF; field bits<5> FRA; field bits<5> FRB; @@ -356,7 +356,7 @@ } class XLForm_2 opcode, bits<10> xo, bit lk, bit ppc64, - bit vmx> : PPC32I { + bit vmx> : I { field bits<5> BO; field bits<5> BI; field bits<2> BH; @@ -390,7 +390,7 @@ // 1.7.8 XFX-Form class XFXForm_1 opcode, bits<10> xo, bit ppc64, bit vmx> - : PPC32I { + : I { field bits<5> ST; field bits<10> SPR; @@ -428,7 +428,7 @@ // 1.7.11 XO-Form class XOForm_1 opcode, bits<9> xo, bit oe, bit rc, - bit ppc64, bit vmx> : PPC32I { + bit ppc64, bit vmx> : I { field bits<5> RT; field bits<5> RA; field bits<5> RB; @@ -468,7 +468,7 @@ // 1.7.12 A-Form class AForm_1 opcode, bits<5> xo, bit rc, bit ppc64, - bit vmx> : PPC32I { + bit vmx> : I { let ArgCount = 4; field bits<5> FRT; field bits<5> FRA; @@ -514,7 +514,7 @@ // 1.7.13 M-Form class MForm_1 opcode, bit rc, bit ppc64, bit vmx> - : PPC32I { + : I { let ArgCount = 5; field bits<5> RS; field bits<5> RA; @@ -543,7 +543,7 @@ //===----------------------------------------------------------------------===// -class Pseudo : PPC32I { +class Pseudo : I { let Name = name; let ArgCount = 0; let PPC64 = 0; @@ -555,5 +555,5 @@ let Arg3Type = Pseudo.Value; let Arg4Type = 0; - let Inst {31-0} = 0; + let Inst{31-0} = 0; } Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp:1.6 llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp:1.7 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp:1.6 Mon Jul 26 16:50:38 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp Tue Aug 10 17:47:03 2004 @@ -26,32 +26,32 @@ unsigned& sourceReg, unsigned& destReg) const { MachineOpCode oc = MI.getOpcode(); - if (oc == PPC32::OR) { // or r1, r2, r2 + if (oc == PPC::OR) { // or r1, r2, r2 assert(MI.getNumOperands() == 3 && MI.getOperand(0).isRegister() && MI.getOperand(1).isRegister() && MI.getOperand(2).isRegister() && - "invalid PPC32 OR instruction!"); + "invalid PPC OR instruction!"); if (MI.getOperand(1).getReg() == MI.getOperand(2).getReg()) { sourceReg = MI.getOperand(1).getReg(); destReg = MI.getOperand(0).getReg(); return true; } - } else if (oc == PPC32::ADDI) { // addi r1, r2, 0 + } else if (oc == PPC::ADDI) { // addi r1, r2, 0 assert(MI.getNumOperands() == 3 && MI.getOperand(0).isRegister() && MI.getOperand(2).isImmediate() && - "invalid PPC32 ADDI instruction!"); + "invalid PPC ADDI instruction!"); if (MI.getOperand(1).isRegister() && MI.getOperand(2).getImmedValue()==0) { sourceReg = MI.getOperand(1).getReg(); destReg = MI.getOperand(0).getReg(); return true; } - } else if (oc == PPC32::FMR) { // fmr r1, r2 + } else if (oc == PPC::FMR) { // fmr r1, r2 assert(MI.getNumOperands() == 2 && MI.getOperand(0).isRegister() && MI.getOperand(1).isRegister() && - "invalid PPC32 FMR instruction"); + "invalid PPC FMR instruction"); sourceReg = MI.getOperand(1).getReg(); destReg = MI.getOperand(0).getReg(); return true; Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.h diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.h:1.3 llvm/lib/Target/PowerPC/PowerPCInstrInfo.h:1.4 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.h:1.3 Tue Jul 27 13:34:11 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.h Tue Aug 10 17:47:03 2004 @@ -20,7 +20,7 @@ namespace llvm { -namespace PPC32II { +namespace PPCII { enum { ArgCountShift = 0, ArgCountMask = 7, @@ -83,13 +83,13 @@ static unsigned invertPPCBranchOpcode(unsigned Opcode) { switch (Opcode) { - default: assert(0 && "Unknown PPC32 branch opcode!"); - case PPC32::BEQ: return PPC32::BNE; - case PPC32::BNE: return PPC32::BEQ; - case PPC32::BLT: return PPC32::BGE; - case PPC32::BGE: return PPC32::BLT; - case PPC32::BGT: return PPC32::BLE; - case PPC32::BLE: return PPC32::BGT; + default: assert(0 && "Unknown PPC branch opcode!"); + case PPC::BEQ: return PPC::BNE; + case PPC::BNE: return PPC::BEQ; + case PPC::BLT: return PPC::BGE; + case PPC::BGE: return PPC::BLT; + case PPC::BGT: return PPC::BLE; + case PPC::BLE: return PPC::BGT; } } }; Index: llvm/lib/Target/PowerPC/PowerPCPEI.cpp diff -u llvm/lib/Target/PowerPC/PowerPCPEI.cpp:1.2 llvm/lib/Target/PowerPC/PowerPCPEI.cpp:1.3 --- llvm/lib/Target/PowerPC/PowerPCPEI.cpp:1.2 Fri Aug 6 02:45:37 2004 +++ llvm/lib/Target/PowerPC/PowerPCPEI.cpp Tue Aug 10 17:47:03 2004 @@ -170,7 +170,7 @@ unsigned RegSize = RegInfo->getRegClass(RegsToSave[i])->getSize(); int FrameIdx; - if (RegsToSave[i] == PPC32::LR) { + if (RegsToSave[i] == PPC::LR) { FrameIdx = FFI->CreateFixedObject(RegSize, 8); // LR lives at +8 } else { Offset -= RegSize; Index: llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp diff -u llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp:1.25 llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp:1.26 --- llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp:1.25 Sun Aug 8 20:24:32 2004 +++ llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp Tue Aug 10 17:47:03 2004 @@ -31,8 +31,8 @@ using namespace llvm; PowerPCRegisterInfo::PowerPCRegisterInfo() - : PowerPCGenRegisterInfo(PPC32::ADJCALLSTACKDOWN, - PPC32::ADJCALLSTACKUP) {} + : PowerPCGenRegisterInfo(PPC::ADJCALLSTACKDOWN, + PPC::ADJCALLSTACKUP) {} static unsigned getIdx(const TargetRegisterClass *RC) { if (RC == PowerPC::GPRCRegisterClass) { @@ -59,12 +59,12 @@ unsigned SrcReg, int FrameIdx, const TargetRegisterClass *RC) const { static const unsigned Opcode[] = { - PPC32::STB, PPC32::STH, PPC32::STW, PPC32::STFS, PPC32::STFD + PPC::STB, PPC::STH, PPC::STW, PPC::STFS, PPC::STFD }; unsigned OC = Opcode[getIdx(RC)]; - if (SrcReg == PPC32::LR) { - MBB.insert(MI, BuildMI(PPC32::MFLR, 0, PPC32::R0)); - MBB.insert(MI, addFrameReference(BuildMI(OC,3).addReg(PPC32::R0),FrameIdx)); + if (SrcReg == PPC::LR) { + MBB.insert(MI, BuildMI(PPC::MFLR, 0, PPC::R0)); + MBB.insert(MI, addFrameReference(BuildMI(OC,3).addReg(PPC::R0),FrameIdx)); return 2; } else { MBB.insert(MI, addFrameReference(BuildMI(OC, 3).addReg(SrcReg),FrameIdx)); @@ -78,12 +78,12 @@ unsigned DestReg, int FrameIdx, const TargetRegisterClass *RC) const { static const unsigned Opcode[] = { - PPC32::LBZ, PPC32::LHZ, PPC32::LWZ, PPC32::LFS, PPC32::LFD + PPC::LBZ, PPC::LHZ, PPC::LWZ, PPC::LFS, PPC::LFD }; unsigned OC = Opcode[getIdx(RC)]; - if (DestReg == PPC32::LR) { - MBB.insert(MI, addFrameReference(BuildMI(OC, 2, PPC32::R0), FrameIdx)); - MBB.insert(MI, BuildMI(PPC32::MTLR, 1).addReg(PPC32::R0)); + if (DestReg == PPC::LR) { + MBB.insert(MI, addFrameReference(BuildMI(OC, 2, PPC::R0), FrameIdx)); + MBB.insert(MI, BuildMI(PPC::MTLR, 1).addReg(PPC::R0)); return 2; } else { MBB.insert(MI, addFrameReference(BuildMI(OC, 2, DestReg), FrameIdx)); @@ -98,9 +98,9 @@ MachineInstr *I; if (RC == PowerPC::GPRCRegisterClass) { - I = BuildMI(PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + I = BuildMI(PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); } else if (RC == PowerPC::FPRCRegisterClass) { - I = BuildMI(PPC32::FMR, 1, DestReg).addReg(SrcReg); + I = BuildMI(PPC::FMR, 1, DestReg).addReg(SrcReg); } else { std::cerr << "Attempt to copy register that is not GPR or FPR"; abort(); @@ -138,12 +138,12 @@ Amount = (Amount+Align-1)/Align*Align; MachineInstr *New; - if (Old->getOpcode() == PPC32::ADJCALLSTACKDOWN) { - New = BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1) + if (Old->getOpcode() == PPC::ADJCALLSTACKDOWN) { + New = BuildMI(PPC::ADDI, 2, PPC::R1).addReg(PPC::R1) .addSImm(-Amount); } else { - assert(Old->getOpcode() == PPC32::ADJCALLSTACKUP); - New = BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1) + assert(Old->getOpcode() == PPC::ADJCALLSTACKUP); + New = BuildMI(PPC::ADDI, 2, PPC::R1).addReg(PPC::R1) .addSImm(Amount); } @@ -168,7 +168,7 @@ int FrameIndex = MI.getOperand(i).getFrameIndex(); // Replace the FrameIndex with base register with GPR1. - MI.SetMachineOperandReg(i, PPC32::R1); + MI.SetMachineOperandReg(i, PPC::R1); // Take into account whether it's an add or mem instruction unsigned OffIdx = (i == 2) ? 1 : 2; @@ -213,7 +213,7 @@ // Add the size of R1 to NumBytes size for the store of R1 to the bottom // of the stack and round the size to a multiple of the alignment. unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment(); - unsigned Size = getRegClass(PPC32::R1)->getSize(); + unsigned Size = getRegClass(PPC::R1)->getSize(); NumBytes = (NumBytes+Size+Align-1)/Align*Align; // Update frame info to pretend that this is part of the stack... @@ -221,18 +221,18 @@ // adjust stack pointer: r1 -= numbytes if (NumBytes <= 32768) { - MI = BuildMI(PPC32::STWU, 3).addReg(PPC32::R1).addSImm(-NumBytes) - .addReg(PPC32::R1); + MI = BuildMI(PPC::STWU, 3).addReg(PPC::R1).addSImm(-NumBytes) + .addReg(PPC::R1); MBB.insert(MBBI, MI); } else { int NegNumbytes = -NumBytes; - MI = BuildMI(PPC32::LIS, 1, PPC32::R0).addSImm(NegNumbytes >> 16); + MI = BuildMI(PPC::LIS, 1, PPC::R0).addSImm(NegNumbytes >> 16); MBB.insert(MBBI, MI); - MI = BuildMI(PPC32::ORI, 2, PPC32::R0).addReg(PPC32::R0) + MI = BuildMI(PPC::ORI, 2, PPC::R0).addReg(PPC::R0) .addImm(NegNumbytes & 0xFFFF); MBB.insert(MBBI, MI); - MI = BuildMI(PPC32::STWUX, 3).addReg(PPC32::R1).addReg(PPC32::R1) - .addReg(PPC32::R0); + MI = BuildMI(PPC::STWUX, 3).addReg(PPC::R1).addReg(PPC::R1) + .addReg(PPC::R0); MBB.insert(MBBI, MI); } } @@ -242,14 +242,14 @@ const MachineFrameInfo *MFI = MF.getFrameInfo(); MachineBasicBlock::iterator MBBI = prior(MBB.end()); MachineInstr *MI; - assert(MBBI->getOpcode() == PPC32::BLR && + assert(MBBI->getOpcode() == PPC::BLR && "Can only insert epilog into returning blocks"); // Get the number of bytes allocated from the FrameInfo... unsigned NumBytes = MFI->getStackSize(); if (NumBytes != 0) { - MI = BuildMI(PPC32::LWZ, 2, PPC32::R1).addSImm(0).addReg(PPC32::R1); + MI = BuildMI(PPC::LWZ, 2, PPC::R1).addSImm(0).addReg(PPC::R1); MBB.insert(MBBI, MI); } } Index: llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td diff -u llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td:1.7 llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td:1.8 --- llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td:1.7 Tue Jul 27 18:29:16 2004 +++ llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td Tue Aug 10 17:47:03 2004 @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// class PPCReg : Register { - let Namespace = "PPC32"; + let Namespace = "PPC"; } // We identify all our registers with a 5-bit ID, for consistency's sake. From brukman at cs.uiuc.edu Tue Aug 10 18:10:31 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 18:10:31 -0500 Subject: [llvm-commits] CVS: llvm/include/llvm/Target/TargetMachine.h Message-ID: <200408102310.SAA21267@zion.cs.uiuc.edu> Changes in directory llvm/include/llvm/Target: TargetMachine.h updated: 1.49 -> 1.50 --- Log message: Add new constructor. --- Diffs of the changes: (+3 -0) Index: llvm/include/llvm/Target/TargetMachine.h diff -u llvm/include/llvm/Target/TargetMachine.h:1.49 llvm/include/llvm/Target/TargetMachine.h:1.50 --- llvm/include/llvm/Target/TargetMachine.h:1.49 Thu Jul 22 20:08:13 2004 +++ llvm/include/llvm/Target/TargetMachine.h Tue Aug 10 18:10:21 2004 @@ -54,6 +54,9 @@ unsigned char ShortAl = 2, unsigned char ByteAl = 1, unsigned char BoolAl = 1); + TargetMachine(const std::string &name, IntrinsicLowering *IL, + const TargetData &TD); + /// This constructor is used for targets that support arbitrary TargetData /// layouts, like the C backend. It initializes the TargetData to match that /// of the specified module. From brukman at cs.uiuc.edu Tue Aug 10 18:10:36 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 18:10:36 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/TargetMachine.cpp Message-ID: <200408102310.SAA21273@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target: TargetMachine.cpp updated: 1.32 -> 1.33 --- Log message: Implement new constructor. --- Diffs of the changes: (+7 -0) Index: llvm/lib/Target/TargetMachine.cpp diff -u llvm/lib/Target/TargetMachine.cpp:1.32 llvm/lib/Target/TargetMachine.cpp:1.33 --- llvm/lib/Target/TargetMachine.cpp:1.32 Thu Jul 22 20:09:52 2004 +++ llvm/lib/Target/TargetMachine.cpp Tue Aug 10 18:10:25 2004 @@ -52,6 +52,13 @@ IntAl, ShortAl, ByteAl, BoolAl) { IL = il ? il : new DefaultIntrinsicLowering(); } + +TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il, + const TargetData &TD) + : Name(name), DataLayout(TD) { + IL = il ? il : new DefaultIntrinsicLowering(); +} + TargetMachine::TargetMachine(const std::string &name, IntrinsicLowering *il, const Module &M) : Name(name), DataLayout(name, &M) { From brukman at cs.uiuc.edu Tue Aug 10 19:09:52 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 19:09:52 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC32.h PPC32JITInfo.h PPC32TargetMachine.cpp PPC32TargetMachine.h PPC32AsmPrinter.cpp PPC32CodeEmitter.cpp PPC32ISelSimple.cpp Message-ID: <200408110009.TAA21997@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC32.h added (r1.1) PPC32JITInfo.h added (r1.1) PPC32TargetMachine.cpp added (r1.1) PPC32TargetMachine.h added (r1.1) PPC32AsmPrinter.cpp updated: 1.33 -> 1.34 PPC32CodeEmitter.cpp updated: 1.2 -> 1.3 PPC32ISelSimple.cpp updated: 1.56 -> 1.57 --- Log message: Breaking up the PowerPC target into 32- and 64-bit subparts, Part I: 32-bit. --- Diffs of the changes: (+277 -29) Index: llvm/lib/Target/PowerPC/PPC32.h diff -c /dev/null llvm/lib/Target/PowerPC/PPC32.h:1.1 *** /dev/null Tue Aug 10 19:09:52 2004 --- llvm/lib/Target/PowerPC/PPC32.h Tue Aug 10 19:09:42 2004 *************** *** 0 **** --- 1,31 ---- + //===-- PPC32.h - Top-level interface for 32-bit 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 contains the entry points for global functions defined in the LLVM + // Darwin/PowerPC back-end. + // + //===----------------------------------------------------------------------===// + + #ifndef TARGET_POWERPC32_H + #define TARGET_POWERPC32_H + + #include "PowerPC.h" + #include + + namespace llvm { + + class FunctionPass; + class TargetMachine; + + FunctionPass *createPPC32ISelSimple(TargetMachine &TM); + FunctionPass *createPPC32AsmPrinter(std::ostream &OS,TargetMachine &TM); + + } // end namespace llvm; + + #endif Index: llvm/lib/Target/PowerPC/PPC32JITInfo.h diff -c /dev/null llvm/lib/Target/PowerPC/PPC32JITInfo.h:1.1 *** /dev/null Tue Aug 10 19:09:52 2004 --- llvm/lib/Target/PowerPC/PPC32JITInfo.h Tue Aug 10 19:09:42 2004 *************** *** 0 **** --- 1,48 ---- + //===- PPC32JITInfo.h - PowerPC/Darwin 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 POWERPC_DARWIN_JITINFO_H + #define POWERPC_DARWIN_JITINFO_H + + #include "PowerPCJITInfo.h" + + namespace llvm { + class TargetMachine; + class IntrinsicLowering; + + class PPC32JITInfo : public PowerPCJITInfo { + public: + PPC32JITInfo(TargetMachine &tm) : PowerPCJITInfo(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/PPC32TargetMachine.cpp diff -c /dev/null llvm/lib/Target/PowerPC/PPC32TargetMachine.cpp:1.1 *** /dev/null Tue Aug 10 19:09:52 2004 --- llvm/lib/Target/PowerPC/PPC32TargetMachine.cpp Tue Aug 10 19:09:42 2004 *************** *** 0 **** --- 1,115 ---- + //===-- 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 "PPC32.h" + #include "PPC32JITInfo.h" + #include "PPC32TargetMachine.h" + #include "llvm/Module.h" + #include "llvm/PassManager.h" + #include "llvm/CodeGen/IntrinsicLowering.h" + #include "llvm/CodeGen/MachineFunction.h" + #include "llvm/CodeGen/Passes.h" + #include "llvm/Target/TargetOptions.h" + #include "llvm/Target/TargetMachineRegistry.h" + #include "llvm/Transforms/Scalar.h" + #include + using namespace llvm; + + namespace { + const std::string PPC32 = "Darwin/PowerPC"; + // Register the target + RegisterTarget + X("powerpc-darwin", " Darwin/PowerPC (experimental)"); + } + + /// PowerPCTargetMachine ctor - Create an ILP32 architecture model + /// + PPC32TargetMachine::PPC32TargetMachine(const Module &M, + IntrinsicLowering *IL) + : PowerPCTargetMachine(PPC32, IL, + TargetData(PPC32,false,4,4,4,4,4,4,2,1,4), + TargetFrameInfo(TargetFrameInfo::StackGrowsDown,16,-4), + PPC32JITInfo(*this)) {} + + /// addPassesToEmitAssembly - Add passes to the specified pass manager + /// to implement a static compiler for this target. + /// + bool PPC32TargetMachine::addPassesToEmitAssembly(PassManager &PM, + std::ostream &Out) { + // FIXME: Implement efficient support for garbage collection intrinsics. + PM.add(createLowerGCPass()); + + // FIXME: Implement the invoke/unwind instructions! + PM.add(createLowerInvokePass()); + + // FIXME: Implement the switch instruction in the instruction selector! + PM.add(createLowerSwitchPass()); + + PM.add(createLowerConstantExpressionsPass()); + + // Make sure that no unreachable blocks are instruction selected. + PM.add(createUnreachableBlockEliminationPass()); + + PM.add(createPPC32ISelSimple(*this)); + + if (PrintMachineCode) + PM.add(createMachineFunctionPrinterPass(&std::cerr)); + + PM.add(createRegisterAllocator()); + + if (PrintMachineCode) + PM.add(createMachineFunctionPrinterPass(&std::cerr)); + + // I want a PowerPC specific prolog/epilog code inserter so I can put the + // fills/spills in the right spots. + PM.add(createPowerPCPEI()); + + // Must run branch selection immediately preceding the printer + PM.add(createPPCBranchSelectionPass()); + PM.add(createPPC32AsmPrinter(Out, *this)); + PM.add(createMachineCodeDeleter()); + return false; + } + + /// addPassesToJITCompile - Add passes to the specified pass manager to + /// implement a fast dynamic compiler for this target. + /// + void PPC32JITInfo::addPassesToJITCompile(FunctionPassManager &PM) { + // FIXME: Implement efficient support for garbage collection intrinsics. + PM.add(createLowerGCPass()); + + // FIXME: Implement the invoke/unwind instructions! + PM.add(createLowerInvokePass()); + + // FIXME: Implement the switch instruction in the instruction selector! + PM.add(createLowerSwitchPass()); + + PM.add(createLowerConstantExpressionsPass()); + + // Make sure that no unreachable blocks are instruction selected. + PM.add(createUnreachableBlockEliminationPass()); + + PM.add(createPPC32ISelSimple(TM)); + PM.add(createRegisterAllocator()); + PM.add(createPrologEpilogCodeInserter()); + } + + unsigned PPC32TargetMachine::getModuleMatchQuality(const Module &M) { + if (M.getEndianness() == Module::BigEndian && + M.getPointerSize() == Module::Pointer32) + return 10; // Direct match + else if (M.getEndianness() != Module::AnyEndianness || + M.getPointerSize() != Module::AnyPointerSize) + return 0; // Match for some other target + + return getJITMatchQuality()/2; + } Index: llvm/lib/Target/PowerPC/PPC32TargetMachine.h diff -c /dev/null llvm/lib/Target/PowerPC/PPC32TargetMachine.h:1.1 *** /dev/null Tue Aug 10 19:09:52 2004 --- llvm/lib/Target/PowerPC/PPC32TargetMachine.h Tue Aug 10 19:09:42 2004 *************** *** 0 **** --- 1,53 ---- + //===-- PPC32TargetMachine.h - PowerPC/Darwin TargetMachine ---*- 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/Darwin specific subclass of TargetMachine. + // + //===----------------------------------------------------------------------===// + + #ifndef POWERPC_DARWIN_TARGETMACHINE_H + #define POWERPC_DARWIN_TARGETMACHINE_H + + #include "llvm/Target/TargetMachine.h" + #include "llvm/Target/TargetFrameInfo.h" + #include "llvm/PassManager.h" + #include "PowerPCTargetMachine.h" + #include + + namespace llvm { + + class GlobalValue; + class IntrinsicLowering; + + class PPC32TargetMachine : public PowerPCTargetMachine { + public: + PPC32TargetMachine(const Module &M, IntrinsicLowering *IL); + + /// 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); + + static unsigned getModuleMatchQuality(const Module &M); + + // Two shared sets between the instruction selector and the printer allow for + // correct linkage on Darwin + std::set CalledFunctions; + std::set AddressTaken; + }; + + } // end namespace llvm + + #endif Index: llvm/lib/Target/PowerPC/PPC32AsmPrinter.cpp diff -u llvm/lib/Target/PowerPC/PPC32AsmPrinter.cpp:1.33 llvm/lib/Target/PowerPC/PPC32AsmPrinter.cpp:1.34 --- llvm/lib/Target/PowerPC/PPC32AsmPrinter.cpp:1.33 Tue Aug 10 17:47:03 2004 +++ llvm/lib/Target/PowerPC/PPC32AsmPrinter.cpp Tue Aug 10 19:09:42 2004 @@ -1,4 +1,4 @@ -//===-- PowerPCAsmPrinter.cpp - Print machine instrs to PowerPC assembly --===// +//===-- PPC32AsmPrinter.cpp - Print machine instrs to PowerPC assembly ----===// // // The LLVM Compiler Infrastructure // @@ -19,7 +19,7 @@ #define DEBUG_TYPE "asmprinter" #include "PowerPC.h" #include "PowerPCInstrInfo.h" -#include "PowerPCTargetMachine.h" +#include "PPC32TargetMachine.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Module.h" @@ -48,7 +48,7 @@ /// Target machine description which we query for reg. names, data /// layout, etc. /// - PowerPCTargetMachine &TM; + PPC32TargetMachine &TM; /// Name-mangler for global names. /// @@ -57,7 +57,7 @@ std::set Strings; Printer(std::ostream &o, TargetMachine &tm) : O(o), - TM(reinterpret_cast(tm)), LabelNumber(0) {} + TM(reinterpret_cast(tm)), LabelNumber(0) {} /// Cache of mangled name for current function. This is /// recalculated at the beginning of each call to @@ -70,7 +70,7 @@ unsigned LabelNumber; virtual const char *getPassName() const { - return "PowerPC Assembly Printer"; + return "PPC32 Assembly Printer"; } void printMachineInstruction(const MachineInstr *MI); @@ -85,12 +85,12 @@ }; } // end of anonymous namespace -/// createPPCAsmPrinterPass - Returns a pass that prints the PPC +/// createPPC32AsmPrinterPass - Returns a pass that prints the PPC /// assembly code for a MachineFunction to the given output stream, /// using the given target machine description. This should work /// regardless of whether the function is in SSA form or not. /// -FunctionPass *createPPCAsmPrinterPass(std::ostream &o,TargetMachine &tm) { +FunctionPass *createPPC32AsmPrinter(std::ostream &o,TargetMachine &tm) { return new Printer(o, tm); } Index: llvm/lib/Target/PowerPC/PPC32CodeEmitter.cpp diff -u llvm/lib/Target/PowerPC/PPC32CodeEmitter.cpp:1.2 llvm/lib/Target/PowerPC/PPC32CodeEmitter.cpp:1.3 --- llvm/lib/Target/PowerPC/PPC32CodeEmitter.cpp:1.2 Mon Aug 9 18:03:59 2004 +++ llvm/lib/Target/PowerPC/PPC32CodeEmitter.cpp Tue Aug 10 19:09:42 2004 @@ -1,4 +1,4 @@ -//===-- PowerPCCodeEmitter.cpp - JIT Code Emitter for PowerPC -----*- C++ -*-=// +//===-- PPC32CodeEmitter.cpp - JIT Code Emitter for PowerPC32 -----*- C++ -*-=// // // The LLVM Compiler Infrastructure // @@ -10,7 +10,8 @@ // //===----------------------------------------------------------------------===// -#include "PowerPCTargetMachine.h" +#include "PPC32JITInfo.h" +#include "PPC32TargetMachine.h" #include "llvm/CodeGen/MachineCodeEmitter.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/Passes.h" @@ -19,12 +20,12 @@ namespace llvm { namespace { - class PowerPCCodeEmitter : public MachineFunctionPass { + class PPC32CodeEmitter : public MachineFunctionPass { TargetMachine &TM; MachineCodeEmitter &MCE; public: - PowerPCCodeEmitter(TargetMachine &T, MachineCodeEmitter &M) + PPC32CodeEmitter(TargetMachine &T, MachineCodeEmitter &M) : TM(T), MCE(M) {} const char *getPassName() const { return "PowerPC Machine Code Emitter"; } @@ -55,17 +56,17 @@ /// of functions. This method should returns true if machine code emission is /// not supported. /// -bool PowerPCTargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM, - MachineCodeEmitter &MCE) { +bool PPC32TargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM, + MachineCodeEmitter &MCE) { // Machine code emitter pass for PowerPC - PM.add(new PowerPCCodeEmitter(*this, MCE)); + PM.add(new PPC32CodeEmitter(*this, MCE)); // Delete machine code for this function after emitting it: PM.add(createMachineCodeDeleter()); // We don't yet support machine code emission return true; } -bool PowerPCCodeEmitter::runOnMachineFunction(MachineFunction &MF) { +bool PPC32CodeEmitter::runOnMachineFunction(MachineFunction &MF) { MCE.startFunction(MF); MCE.emitConstantPool(MF.getConstantPool()); for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I) @@ -74,24 +75,24 @@ return false; } -void PowerPCCodeEmitter::emitBasicBlock(MachineBasicBlock &MBB) { +void PPC32CodeEmitter::emitBasicBlock(MachineBasicBlock &MBB) { for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E; ++I) emitWord(getBinaryCodeForInstr(*I)); } -unsigned PowerPCCodeEmitter::getValueBit(int64_t Val, unsigned bit) { +unsigned PPC32CodeEmitter::getValueBit(int64_t Val, unsigned bit) { Val >>= bit; return (Val & 1); } -void *PowerPCJITInfo::getJITStubForFunction(Function *F, - MachineCodeEmitter &MCE) { - assert (0 && "PowerPCJITInfo::getJITStubForFunction not implemented"); +void *PPC32JITInfo::getJITStubForFunction(Function *F, + MachineCodeEmitter &MCE) { + assert (0 && "PPC32JITInfo::getJITStubForFunction not implemented"); return 0; } -void PowerPCJITInfo::replaceMachineCodeForFunction (void *Old, void *New) { - assert (0 && "PowerPCJITInfo::replaceMachineCodeForFunction not implemented"); +void PPC32JITInfo::replaceMachineCodeForFunction (void *Old, void *New) { + assert (0 && "PPC32JITInfo::replaceMachineCodeForFunction not implemented"); } //#include "PowerPCGenCodeEmitter.inc" Index: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp diff -u llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.56 llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.57 --- llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.56 Tue Aug 10 17:47:03 2004 +++ llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp Tue Aug 10 19:09:42 2004 @@ -11,7 +11,8 @@ #include "PowerPC.h" #include "PowerPCInstrBuilder.h" #include "PowerPCInstrInfo.h" -#include "PowerPCTargetMachine.h" +#include "PPC32.h" +#include "PPC32TargetMachine.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" #include "llvm/Function.h" @@ -74,7 +75,7 @@ namespace { struct ISel : public FunctionPass, InstVisitor { - PowerPCTargetMachine &TM; + PPC32TargetMachine &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 @@ -98,7 +99,7 @@ unsigned GlobalBaseReg; bool GlobalBaseInitialized; - ISel(TargetMachine &tm) : TM(reinterpret_cast(tm)), + ISel(TargetMachine &tm) : TM(reinterpret_cast(tm)), F(0), BB(0) {} bool doInitialization(Module &M) { @@ -3390,10 +3391,9 @@ TM.CalledFunctions.insert(freeFn); } -/// createPPCSimpleInstructionSelector - This pass converts an LLVM function -/// into a machine code representation is a very simple peep-hole fashion. The -/// generated code sucks but the implementation is nice and simple. +/// createPPC32ISelSimple - This pass converts an LLVM function into a machine +/// code representation is a very simple peep-hole fashion. /// -FunctionPass *llvm::createPPCSimpleInstructionSelector(TargetMachine &TM) { +FunctionPass *llvm::createPPC32ISelSimple(TargetMachine &TM) { return new ISel(TM); } From brukman at cs.uiuc.edu Tue Aug 10 19:10:51 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 19:10:51 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC64.h PPC64CodeEmitter.cpp PPC64JITInfo.h PPC64TargetMachine.cpp PPC64TargetMachine.h Message-ID: <200408110010.TAA22050@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC64.h added (r1.1) PPC64CodeEmitter.cpp added (r1.1) PPC64JITInfo.h added (r1.1) PPC64TargetMachine.cpp added (r1.1) PPC64TargetMachine.h added (r1.1) --- Log message: Breaking up the PowerPC target into 32- and 64-bit subparts: Part II: 64-bit. --- Diffs of the changes: (+269 -0) Index: llvm/lib/Target/PowerPC/PPC64.h diff -c /dev/null llvm/lib/Target/PowerPC/PPC64.h:1.1 *** /dev/null Tue Aug 10 19:10:51 2004 --- llvm/lib/Target/PowerPC/PPC64.h Tue Aug 10 19:10:41 2004 *************** *** 0 **** --- 1,20 ---- + //===-- PPC64.h - Top-level interface for AIX/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 contains the entry points for global functions defined in the LLVM + // PowerPC 64-bit back-end. + // + //===----------------------------------------------------------------------===// + + #ifndef TARGET_POWERPC_AIX_H + #define TARGET_POWERPC_AIX_H + + #include "PowerPC.h" + + #endif Index: llvm/lib/Target/PowerPC/PPC64CodeEmitter.cpp diff -c /dev/null llvm/lib/Target/PowerPC/PPC64CodeEmitter.cpp:1.1 *** /dev/null Tue Aug 10 19:10:51 2004 --- llvm/lib/Target/PowerPC/PPC64CodeEmitter.cpp Tue Aug 10 19:10:41 2004 *************** *** 0 **** --- 1,44 ---- + //===-- PPC64CodeEmitter.cpp - JIT Code Emitter for PPC64 -----*- 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 "PPC64JITInfo.h" + #include "PPC64TargetMachine.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 PPC64TargetMachine::addPassesToEmitMachineCode(FunctionPassManager &PM, + MachineCodeEmitter &MCE) { + return true; + // It should go something like this: + // PM.add(new Emitter(MCE)); // Machine code emitter pass for PPC64 + // Delete machine code for this function after emitting it: + // PM.add(createMachineCodeDeleter()); + } + + void *PPC64JITInfo::getJITStubForFunction(Function *F, + MachineCodeEmitter &MCE) { + assert (0 && "PPC64JITInfo::getJITStubForFunction not implemented"); + return 0; + } + + void PPC64JITInfo::replaceMachineCodeForFunction (void *Old, void *New) { + assert (0 && "PPC64JITInfo::replaceMachineCodeForFunction not implemented"); + } + + } // end llvm namespace + Index: llvm/lib/Target/PowerPC/PPC64JITInfo.h diff -c /dev/null llvm/lib/Target/PowerPC/PPC64JITInfo.h:1.1 *** /dev/null Tue Aug 10 19:10:51 2004 --- llvm/lib/Target/PowerPC/PPC64JITInfo.h Tue Aug 10 19:10:41 2004 *************** *** 0 **** --- 1,47 ---- + //===- PPC64JITInfo.h - PowerPC/AIX 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/AIX implementation of the TargetJITInfo class. + // + //===----------------------------------------------------------------------===// + + #ifndef POWERPC_AIX_JITINFO_H + #define POWERPC_AIX_JITINFO_H + + #include "PowerPCJITInfo.h" + + namespace llvm { + class TargetMachine; + + class PPC64JITInfo : public PowerPCJITInfo { + public: + PPC64JITInfo(TargetMachine &tm) : PowerPCJITInfo(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/PPC64TargetMachine.cpp diff -c /dev/null llvm/lib/Target/PowerPC/PPC64TargetMachine.cpp:1.1 *** /dev/null Tue Aug 10 19:10:51 2004 --- llvm/lib/Target/PowerPC/PPC64TargetMachine.cpp Tue Aug 10 19:10:41 2004 *************** *** 0 **** --- 1,117 ---- + //===-- PPC64TargetMachine.cpp - Define TargetMachine for AIX/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 "PowerPC.h" + #include "PPC64JITInfo.h" + #include "PPC64TargetMachine.h" + #include "llvm/Module.h" + #include "llvm/PassManager.h" + #include "llvm/CodeGen/IntrinsicLowering.h" + #include "llvm/CodeGen/MachineFunction.h" + #include "llvm/CodeGen/Passes.h" + #include "llvm/Target/TargetOptions.h" + #include "llvm/Target/TargetMachineRegistry.h" + #include "llvm/Transforms/Scalar.h" + #include + using namespace llvm; + + namespace { + const std::string PPC64 = "AIX/PowerPC"; + // Register the target + RegisterTarget + X("powerpc-aix", " AIX/PowerPC (experimental)"); + } + + /// PPC64TargetMachine ctor + /// + PPC64TargetMachine::PPC64TargetMachine(const Module &M, IntrinsicLowering *IL) + // FIXME: this is wrong! + : PowerPCTargetMachine(PPC64, IL, + TargetData(PPC64,false,8,4,4,4,4,4,2,1,4), + TargetFrameInfo(TargetFrameInfo::StackGrowsDown,16,-4), + PPC64JITInfo(*this)) {} + + /// addPassesToEmitAssembly - Add passes to the specified pass manager + /// to implement a static compiler for this target. + /// + bool PPC64TargetMachine::addPassesToEmitAssembly(PassManager &PM, + std::ostream &Out) { + // FIXME: Implement efficient support for garbage collection intrinsics. + PM.add(createLowerGCPass()); + + // FIXME: Implement the invoke/unwind instructions! + PM.add(createLowerInvokePass()); + + // FIXME: Implement the switch instruction in the instruction selector! + PM.add(createLowerSwitchPass()); + + PM.add(createLowerConstantExpressionsPass()); + + // Make sure that no unreachable blocks are instruction selected. + PM.add(createUnreachableBlockEliminationPass()); + + // FIXME: instruction selector! + //PM.add(createPPCSimpleInstructionSelector(*this)); + + if (PrintMachineCode) + PM.add(createMachineFunctionPrinterPass(&std::cerr)); + + PM.add(createRegisterAllocator()); + + if (PrintMachineCode) + PM.add(createMachineFunctionPrinterPass(&std::cerr)); + + // I want a PowerPC specific prolog/epilog code inserter so I can put the + // fills/spills in the right spots. + //PM.add(createPowerPCPEI()); + + // Must run branch selection immediately preceding the printer + //PM.add(createPPCBranchSelectionPass()); + //PM.add(createPPC32AsmPrinterPass(Out, *this)); + PM.add(createMachineCodeDeleter()); + return false; + } + + /// addPassesToJITCompile - Add passes to the specified pass manager to + /// implement a fast dynamic compiler for this target. + /// + void PPC64JITInfo::addPassesToJITCompile(FunctionPassManager &PM) { + // FIXME: Implement efficient support for garbage collection intrinsics. + PM.add(createLowerGCPass()); + + // FIXME: Implement the invoke/unwind instructions! + PM.add(createLowerInvokePass()); + + // FIXME: Implement the switch instruction in the instruction selector! + PM.add(createLowerSwitchPass()); + + PM.add(createLowerConstantExpressionsPass()); + + // Make sure that no unreachable blocks are instruction selected. + PM.add(createUnreachableBlockEliminationPass()); + + // FIXME: ISel + //PM.add(createPPCSimpleInstructionSelector(TM)); + PM.add(createRegisterAllocator()); + PM.add(createPrologEpilogCodeInserter()); + } + + unsigned PPC64TargetMachine::getModuleMatchQuality(const Module &M) { + if (M.getEndianness() == Module::BigEndian && + M.getPointerSize() == Module::Pointer64) + return 10; // Direct match + else if (M.getEndianness() != Module::AnyEndianness || + M.getPointerSize() != Module::AnyPointerSize) + return 0; // Match for some other target + + return getJITMatchQuality()/2; + } Index: llvm/lib/Target/PowerPC/PPC64TargetMachine.h diff -c /dev/null llvm/lib/Target/PowerPC/PPC64TargetMachine.h:1.1 *** /dev/null Tue Aug 10 19:10:51 2004 --- llvm/lib/Target/PowerPC/PPC64TargetMachine.h Tue Aug 10 19:10:41 2004 *************** *** 0 **** --- 1,41 ---- + //===-- PPC64TargetMachine.h - Define AIX/PowerPC TargetMachine --*- 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/AIX specific subclass of TargetMachine. + // + //===----------------------------------------------------------------------===// + + #ifndef POWERPC_AIX_TARGETMACHINE_H + #define POWERPC_AIX_TARGETMACHINE_H + + #include "PowerPCTargetMachine.h" + + namespace llvm { + + class PPC64TargetMachine : public PowerPCTargetMachine { + public: + PPC64TargetMachine(const Module &M, IntrinsicLowering *IL); + + /// 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); + + static unsigned getModuleMatchQuality(const Module &M); + }; + + } // end namespace llvm + + #endif From brukman at cs.uiuc.edu Tue Aug 10 19:11:36 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Tue, 10 Aug 2004 19:11:36 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPC.h PowerPCInstrInfo.h PowerPCJITInfo.h PowerPCTargetMachine.cpp PowerPCTargetMachine.h PowerPCAsmPrinter.cpp PowerPCCodeEmitter.cpp PowerPCISelSimple.cpp Message-ID: <200408110011.TAA22119@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPC.h updated: 1.4 -> 1.5 PowerPCInstrInfo.h updated: 1.4 -> 1.5 PowerPCJITInfo.h updated: 1.1.1.1 -> 1.2 PowerPCTargetMachine.cpp updated: 1.23 -> 1.24 PowerPCTargetMachine.h updated: 1.3 -> 1.4 PowerPCAsmPrinter.cpp (r1.33) removed PowerPCCodeEmitter.cpp (r1.2) removed PowerPCISelSimple.cpp (r1.56) removed --- Log message: Breaking up the PowerPC target into 32- and 64-bit subparts, Part III: the rest. --- Diffs of the changes: (+26 -114) Index: llvm/lib/Target/PowerPC/PowerPC.h diff -u llvm/lib/Target/PowerPC/PowerPC.h:1.4 llvm/lib/Target/PowerPC/PowerPC.h:1.5 --- llvm/lib/Target/PowerPC/PowerPC.h:1.4 Mon Aug 9 17:27:45 2004 +++ llvm/lib/Target/PowerPC/PowerPC.h Tue Aug 10 19:11:25 2004 @@ -15,19 +15,13 @@ #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 *createPPCSimpleInstructionSelector(TargetMachine &TM); -FunctionPass *createPPCAsmPrinterPass(std::ostream &OS, TargetMachine &TM); FunctionPass *createPowerPCPEI(); FunctionPass *createPPCBranchSelectionPass(); + } // end namespace llvm; // Defines symbolic names for PowerPC registers. This defines a mapping from Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.h diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.h:1.4 llvm/lib/Target/PowerPC/PowerPCInstrInfo.h:1.5 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.h:1.4 Tue Aug 10 17:47:03 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.h Tue Aug 10 19:11:25 2004 @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef POWERPCINSTRUCTIONINFO_H -#define POWERPCINSTRUCTIONINFO_H +#ifndef POWERPC_INSTRUCTIONINFO_H +#define POWERPC_INSTRUCTIONINFO_H #include "PowerPC.h" #include "PowerPCRegisterInfo.h" Index: llvm/lib/Target/PowerPC/PowerPCJITInfo.h diff -u llvm/lib/Target/PowerPC/PowerPCJITInfo.h:1.1.1.1 llvm/lib/Target/PowerPC/PowerPCJITInfo.h:1.2 --- llvm/lib/Target/PowerPC/PowerPCJITInfo.h:1.1.1.1 Mon Jun 21 11:55:26 2004 +++ llvm/lib/Target/PowerPC/PowerPCJITInfo.h Tue Aug 10 19:11:25 2004 @@ -11,16 +11,16 @@ // //===----------------------------------------------------------------------===// -#ifndef POWERPCJITINFO_H -#define POWERPCJITINFO_H +#ifndef POWERPC_JITINFO_H +#define POWERPC_JITINFO_H #include "llvm/Target/TargetJITInfo.h" namespace llvm { class TargetMachine; - class IntrinsicLowering; class PowerPCJITInfo : public TargetJITInfo { + protected: TargetMachine &TM; public: PowerPCJITInfo(TargetMachine &tm) : TM(tm) {} Index: llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp diff -u llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.23 llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.24 --- llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.23 Mon Aug 9 17:27:45 2004 +++ llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp Tue Aug 10 19:11:25 2004 @@ -23,10 +23,12 @@ #include using namespace llvm; -namespace { - // Register the target. - RegisterTarget X("powerpc", " PowerPC (experimental)"); -} +PowerPCTargetMachine::PowerPCTargetMachine(const std::string &name, + IntrinsicLowering *IL, + const TargetData &TD, + const TargetFrameInfo &TFI, + const PowerPCJITInfo &TJI) + : TargetMachine(name, IL, TD), FrameInfo(TFI), JITInfo(TJI) {} unsigned PowerPCTargetMachine::getJITMatchQuality() { #if defined(__POWERPC__) || defined (__ppc__) || defined(_POWER) @@ -35,86 +37,17 @@ return 0; #endif } - -unsigned PowerPCTargetMachine::getModuleMatchQuality(const Module &M) { - if (M.getEndianness() == Module::BigEndian && - M.getPointerSize() == Module::Pointer32) - return 10; // Direct match - else if (M.getEndianness() != Module::AnyEndianness || - M.getPointerSize() != Module::AnyPointerSize) - return 0; // Match for some other target - return getJITMatchQuality()/2; +void PowerPCJITInfo::addPassesToJITCompile(FunctionPassManager &PM) { + assert(0 && "Cannot execute PowerPCJITInfo::addPassesToJITCompile()"); } - -/// PowerPCTargetMachine ctor - Create an ILP32 architecture model -/// -PowerPCTargetMachine::PowerPCTargetMachine(const Module &M, - IntrinsicLowering *IL) - : TargetMachine("PowerPC", IL, false, 4, 4, 4, 4, 4, 4, 2, 1, 4), - FrameInfo(TargetFrameInfo::StackGrowsDown, 16, -4), JITInfo(*this) { +void PowerPCJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { + assert(0 && "Cannot execute PowerPCJITInfo::replaceMachineCodeForFunction()"); } -/// addPassesToEmitAssembly - Add passes to the specified pass manager -/// to implement a static compiler for this target. -/// -bool PowerPCTargetMachine::addPassesToEmitAssembly(PassManager &PM, - std::ostream &Out) { - // FIXME: Implement efficient support for garbage collection intrinsics. - PM.add(createLowerGCPass()); - - // FIXME: Implement the invoke/unwind instructions! - PM.add(createLowerInvokePass()); - - // FIXME: Implement the switch instruction in the instruction selector! - PM.add(createLowerSwitchPass()); - - PM.add(createLowerConstantExpressionsPass()); - - // Make sure that no unreachable blocks are instruction selected. - PM.add(createUnreachableBlockEliminationPass()); - - PM.add(createPPCSimpleInstructionSelector(*this)); - - if (PrintMachineCode) - PM.add(createMachineFunctionPrinterPass(&std::cerr)); - - PM.add(createRegisterAllocator()); - - if (PrintMachineCode) - PM.add(createMachineFunctionPrinterPass(&std::cerr)); - - // I want a PowerPC specific prolog/epilog code inserter so I can put the - // fills/spills in the right spots. - PM.add(createPowerPCPEI()); - - // Must run branch selection immediately preceding the printer - PM.add(createPPCBranchSelectionPass()); - PM.add(createPPCAsmPrinterPass(Out, *this)); - PM.add(createMachineCodeDeleter()); - return false; -} - -/// addPassesToJITCompile - Add passes to the specified pass manager to -/// implement a fast dynamic compiler for this target. -/// -void PowerPCJITInfo::addPassesToJITCompile(FunctionPassManager &PM) { - // FIXME: Implement efficient support for garbage collection intrinsics. - PM.add(createLowerGCPass()); - - // FIXME: Implement the invoke/unwind instructions! - PM.add(createLowerInvokePass()); - - // FIXME: Implement the switch instruction in the instruction selector! - PM.add(createLowerSwitchPass()); - - PM.add(createLowerConstantExpressionsPass()); - - // Make sure that no unreachable blocks are instruction selected. - PM.add(createUnreachableBlockEliminationPass()); - - PM.add(createPPCSimpleInstructionSelector(TM)); - PM.add(createRegisterAllocator()); - PM.add(createPrologEpilogCodeInserter()); +void *PowerPCJITInfo::getJITStubForFunction(Function *F, + MachineCodeEmitter &MCE) { + assert(0 && "Cannot execute PowerPCJITInfo::getJITStubForFunction()"); + return 0; } 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 Jul 23 11:08:20 2004 +++ llvm/lib/Target/PowerPC/PowerPCTargetMachine.h Tue Aug 10 19:11:25 2004 @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#ifndef POWERPCTARGETMACHINE_H -#define POWERPCTARGETMACHINE_H +#ifndef POWERPC_TARGETMACHINE_H +#define POWERPC_TARGETMACHINE_H #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetFrameInfo.h" @@ -31,9 +31,11 @@ TargetFrameInfo FrameInfo; PowerPCJITInfo JITInfo; +protected: + PowerPCTargetMachine(const std::string &name, IntrinsicLowering *IL, + const TargetData &TD, const TargetFrameInfo &TFI, + const PowerPCJITInfo &TJI); 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 { @@ -43,24 +45,7 @@ return &JITInfo; } - /// 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); - - static unsigned getModuleMatchQuality(const Module &M); static unsigned getJITMatchQuality(); - - // Two shared sets between the instruction selector and the printer allow for - // correct linkage on Darwin - std::set CalledFunctions; - std::set AddressTaken; }; } // end namespace llvm From lattner at cs.uiuc.edu Tue Aug 10 19:50:02 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 19:50:02 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/InstCombine/2004-08-10-BoolSetCC.ll Message-ID: <200408110050.TAA26587@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/InstCombine: 2004-08-10-BoolSetCC.ll added (r1.1) --- Log message: New testcase that instcombine is getting wrong --- Diffs of the changes: (+6 -0) Index: llvm/test/Regression/Transforms/InstCombine/2004-08-10-BoolSetCC.ll diff -c /dev/null llvm/test/Regression/Transforms/InstCombine/2004-08-10-BoolSetCC.ll:1.1 *** /dev/null Tue Aug 10 19:50:00 2004 --- llvm/test/Regression/Transforms/InstCombine/2004-08-10-BoolSetCC.ll Tue Aug 10 19:49:50 2004 *************** *** 0 **** --- 1,6 ---- + ; RUN: llvm-as < %s| opt -instcombine | llvm-dis | grep 'ret bool false' + bool %test(bool %V) { + %Y = setlt bool %V, false + ret bool %Y + } + From lattner at cs.uiuc.edu Tue Aug 10 19:51:02 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 19:51:02 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Scalar/InstructionCombining.cpp Message-ID: <200408110051.TAA26598@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Scalar: InstructionCombining.cpp updated: 1.238 -> 1.239 --- Log message: Fix InstCombine/2004-08-10-BoolSetCC.ll, a bug that is miscompiling 176.gcc. Note that this is apparently not the only bug miscompiling gcc though. :( --- Diffs of the changes: (+21 -22) Index: llvm/lib/Transforms/Scalar/InstructionCombining.cpp diff -u llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.238 llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.239 --- llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.238 Mon Aug 9 16:05:48 2004 +++ llvm/lib/Transforms/Scalar/InstructionCombining.cpp Tue Aug 10 19:50:51 2004 @@ -1392,34 +1392,33 @@ // setcc's with boolean values can always be turned into bitwise operations if (Ty == Type::BoolTy) { - // If this is <, >, or !=, we can change this into a simple xor instruction - if (!isTrueWhenEqual(I)) - return BinaryOperator::createXor(Op0, Op1); - - // Otherwise we need to make a temporary intermediate instruction and insert - // it into the instruction stream. This is what we are after: - // - // seteq bool %A, %B -> ~(A^B) - // setle bool %A, %B -> ~A | B - // setge bool %A, %B -> A | ~B - // - if (I.getOpcode() == Instruction::SetEQ) { // seteq case + switch (I.getOpcode()) { + default: assert(0 && "Invalid setcc instruction!"); + case Instruction::SetEQ: { // seteq bool %A, %B -> ~(A^B) Instruction *Xor = BinaryOperator::createXor(Op0, Op1, I.getName()+"tmp"); InsertNewInstBefore(Xor, I); return BinaryOperator::createNot(Xor); } + case Instruction::SetNE: + return BinaryOperator::createXor(Op0, Op1); - // Handle the setXe cases... - assert(I.getOpcode() == Instruction::SetGE || - I.getOpcode() == Instruction::SetLE); - - if (I.getOpcode() == Instruction::SetGE) + case Instruction::SetGT: + std::swap(Op0, Op1); // Change setgt -> setlt + // FALL THROUGH + case Instruction::SetLT: { // setlt bool A, B -> ~X & Y + Instruction *Not = BinaryOperator::createNot(Op0, I.getName()+"tmp"); + InsertNewInstBefore(Not, I); + return BinaryOperator::createAnd(Not, Op1); + } + case Instruction::SetGE: std::swap(Op0, Op1); // Change setge -> setle - - // Now we just have the SetLE case. - Instruction *Not = BinaryOperator::createNot(Op0, I.getName()+"tmp"); - InsertNewInstBefore(Not, I); - return BinaryOperator::createOr(Not, Op1); + // FALL THROUGH + case Instruction::SetLE: { // setle bool %A, %B -> ~A | B + Instruction *Not = BinaryOperator::createNot(Op0, I.getName()+"tmp"); + InsertNewInstBefore(Not, I); + return BinaryOperator::createOr(Not, Op1); + } + } } // See if we are doing a comparison between a constant and an instruction that From criswell at cs.uiuc.edu Tue Aug 10 20:23:33 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue, 10 Aug 2004 20:23:33 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/lib/Transforms/Scalar/InstructionCombining.cpp Message-ID: <200408110123.UAA25404@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Scalar: InstructionCombining.cpp updated: 1.237.2.1 -> 1.237.2.2 --- Log message: Merged in revision 1.239 from mainline. --- Diffs of the changes: (+21 -22) Index: llvm/lib/Transforms/Scalar/InstructionCombining.cpp diff -u llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.237.2.1 llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.237.2.2 --- llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.237.2.1 Mon Aug 9 16:34:34 2004 +++ llvm/lib/Transforms/Scalar/InstructionCombining.cpp Tue Aug 10 20:23:22 2004 @@ -1392,34 +1392,33 @@ // setcc's with boolean values can always be turned into bitwise operations if (Ty == Type::BoolTy) { - // If this is <, >, or !=, we can change this into a simple xor instruction - if (!isTrueWhenEqual(I)) - return BinaryOperator::createXor(Op0, Op1); - - // Otherwise we need to make a temporary intermediate instruction and insert - // it into the instruction stream. This is what we are after: - // - // seteq bool %A, %B -> ~(A^B) - // setle bool %A, %B -> ~A | B - // setge bool %A, %B -> A | ~B - // - if (I.getOpcode() == Instruction::SetEQ) { // seteq case + switch (I.getOpcode()) { + default: assert(0 && "Invalid setcc instruction!"); + case Instruction::SetEQ: { // seteq bool %A, %B -> ~(A^B) Instruction *Xor = BinaryOperator::createXor(Op0, Op1, I.getName()+"tmp"); InsertNewInstBefore(Xor, I); return BinaryOperator::createNot(Xor); } + case Instruction::SetNE: + return BinaryOperator::createXor(Op0, Op1); - // Handle the setXe cases... - assert(I.getOpcode() == Instruction::SetGE || - I.getOpcode() == Instruction::SetLE); - - if (I.getOpcode() == Instruction::SetGE) + case Instruction::SetGT: + std::swap(Op0, Op1); // Change setgt -> setlt + // FALL THROUGH + case Instruction::SetLT: { // setlt bool A, B -> ~X & Y + Instruction *Not = BinaryOperator::createNot(Op0, I.getName()+"tmp"); + InsertNewInstBefore(Not, I); + return BinaryOperator::createAnd(Not, Op1); + } + case Instruction::SetGE: std::swap(Op0, Op1); // Change setge -> setle - - // Now we just have the SetLE case. - Instruction *Not = BinaryOperator::createNot(Op0, I.getName()+"tmp"); - InsertNewInstBefore(Not, I); - return BinaryOperator::createOr(Not, Op1); + // FALL THROUGH + case Instruction::SetLE: { // setle bool %A, %B -> ~A | B + Instruction *Not = BinaryOperator::createNot(Op0, I.getName()+"tmp"); + InsertNewInstBefore(Not, I); + return BinaryOperator::createOr(Not, Op1); + } + } } // See if we are doing a comparison between a constant and an instruction that From criswell at cs.uiuc.edu Tue Aug 10 20:28:15 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Tue, 10 Aug 2004 20:28:15 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/test/Regression/Transforms/InstCombine/2004-08-10-BoolSetCC.ll Message-ID: <200408110128.UAA25523@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/InstCombine: 2004-08-10-BoolSetCC.ll added (r1.1.2.1) --- Log message: Adding 2004-08-10-BoolSetCC.ll (written by Chris) as a new regression test. Merged from mainline. --- Diffs of the changes: (+6 -0) Index: llvm/test/Regression/Transforms/InstCombine/2004-08-10-BoolSetCC.ll diff -c /dev/null llvm/test/Regression/Transforms/InstCombine/2004-08-10-BoolSetCC.ll:1.1.2.1 *** /dev/null Tue Aug 10 20:28:15 2004 --- llvm/test/Regression/Transforms/InstCombine/2004-08-10-BoolSetCC.ll Tue Aug 10 20:28:05 2004 *************** *** 0 **** --- 1,6 ---- + ; RUN: llvm-as < %s| opt -instcombine | llvm-dis | grep 'ret bool false' + bool %test(bool %V) { + %Y = setlt bool %V, false + ret bool %Y + } + From lattner at cs.uiuc.edu Tue Aug 10 20:53:44 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 20:53:44 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/Target.td Message-ID: <200408110153.UAA25637@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target: Target.td updated: 1.31 -> 1.32 --- Log message: Fill out immediate operand classes, add a new Operand class --- Diffs of the changes: (+14 -4) Index: llvm/lib/Target/Target.td diff -u llvm/lib/Target/Target.td:1.31 llvm/lib/Target/Target.td:1.32 --- llvm/lib/Target/Target.td:1.31 Mon Aug 9 14:13:22 2004 +++ llvm/lib/Target/Target.td Tue Aug 10 20:53:34 2004 @@ -151,10 +151,20 @@ /// list for an instruction. This should be used like this: /// (ops R32:$dst, R32:$src) or something similar. def ops; -def i8imm; -def i16imm; -def i32imm; -def i64imm; + +/// Operand Types - These provide the built-in operand types that may be used +/// by a target. Targets can optionally provide their own operand types as +/// needed, though this should not be needed for RISC targets. +class Operand { + int NumMIOperands = 1; + ValueType Type = ty; + string PrintMethod = "printOperand"; +} + +def i8imm : Operand; +def i16imm : Operand; +def i32imm : Operand; +def i64imm : Operand; //===----------------------------------------------------------------------===// // Target - This class contains the "global" target information From lattner at cs.uiuc.edu Tue Aug 10 20:54:08 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 20:54:08 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/CodeGenTarget.cpp Message-ID: <200408110154.UAA25650@zion.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: CodeGenTarget.cpp updated: 1.12 -> 1.13 --- Log message: Remove special case hacks --- Diffs of the changes: (+2 -8) Index: llvm/utils/TableGen/CodeGenTarget.cpp diff -u llvm/utils/TableGen/CodeGenTarget.cpp:1.12 llvm/utils/TableGen/CodeGenTarget.cpp:1.13 --- llvm/utils/TableGen/CodeGenTarget.cpp:1.12 Sun Aug 1 02:42:39 2004 +++ llvm/utils/TableGen/CodeGenTarget.cpp Tue Aug 10 20:53:58 2004 @@ -138,14 +138,8 @@ MVT::ValueType Ty; if (Rec->isSubClassOf("RegisterClass")) Ty = getValueType(Rec->getValueAsDef("RegType")); - else if (Rec->getName() == "i8imm") - Ty = MVT::i8; - else if (Rec->getName() == "i16imm") - Ty = MVT::i16; - else if (Rec->getName() == "i32imm") - Ty = MVT::i32; - else if (Rec->getName() == "i64imm") - Ty = MVT::i64; + else if (Rec->isSubClassOf("Operand")) + Ty = getValueType(Rec->getValueAsDef("Type")); else throw "Unknown operand class '" + Rec->getName() + "' in instruction '" + R->getName() + "' instruction!"; From lattner at cs.uiuc.edu Tue Aug 10 21:23:35 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 21:23:35 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/AsmWriterEmitter.cpp Message-ID: <200408110223.VAA06567@apoc.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: AsmWriterEmitter.cpp updated: 1.3 -> 1.4 --- Log message: change how we invoke the printer. Instead of passing in the MO directly, pass in the MI, operand number, and the type of the operand. --- Diffs of the changes: (+2 -1) Index: llvm/utils/TableGen/AsmWriterEmitter.cpp diff -u llvm/utils/TableGen/AsmWriterEmitter.cpp:1.3 llvm/utils/TableGen/AsmWriterEmitter.cpp:1.4 --- llvm/utils/TableGen/AsmWriterEmitter.cpp:1.3 Sun Aug 1 03:55:34 2004 +++ llvm/utils/TableGen/AsmWriterEmitter.cpp Tue Aug 10 21:23:23 2004 @@ -82,7 +82,8 @@ --OpNo; } - O << "; printOperand(MI->getOperand(" << OpNo << "), MVT::" + O << "; " << I->second.OperandList[OpNo].PrinterMethodName + << "(MI, " << I->second.OperandList[OpNo].MIOperandNo << ", MVT::" << getName(I->second.OperandList[OpNo].Ty) << "); O "; LastEmitted = VarEnd; } From lattner at cs.uiuc.edu Tue Aug 10 21:23:50 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 21:23:50 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/CodeGenTarget.cpp CodeGenInstruction.h Message-ID: <200408110223.VAA06573@apoc.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: CodeGenTarget.cpp updated: 1.13 -> 1.14 CodeGenInstruction.h updated: 1.2 -> 1.3 --- Log message: Start parsing more information from the Operand information --- Diffs of the changes: (+35 -8) Index: llvm/utils/TableGen/CodeGenTarget.cpp diff -u llvm/utils/TableGen/CodeGenTarget.cpp:1.13 llvm/utils/TableGen/CodeGenTarget.cpp:1.14 --- llvm/utils/TableGen/CodeGenTarget.cpp:1.13 Tue Aug 10 20:53:58 2004 +++ llvm/utils/TableGen/CodeGenTarget.cpp Tue Aug 10 21:22:39 2004 @@ -132,19 +132,26 @@ try { DagInit *DI = R->getValueAsDag("OperandList"); + unsigned MIOperandNo = 0; for (unsigned i = 0, e = DI->getNumArgs(); i != e; ++i) if (DefInit *Arg = dynamic_cast(DI->getArg(i))) { Record *Rec = Arg->getDef(); MVT::ValueType Ty; + std::string PrintMethod = "printOperand"; + unsigned NumOps = 1; if (Rec->isSubClassOf("RegisterClass")) Ty = getValueType(Rec->getValueAsDef("RegType")); - else if (Rec->isSubClassOf("Operand")) + else if (Rec->isSubClassOf("Operand")) { Ty = getValueType(Rec->getValueAsDef("Type")); - else + PrintMethod = Rec->getValueAsString("PrintMethod"); + NumOps = Rec->getValueAsInt("NumMIOperands"); + } else throw "Unknown operand class '" + Rec->getName() + "' in instruction '" + R->getName() + "' instruction!"; - OperandList.push_back(OperandInfo(Rec, Ty, DI->getArgName(i))); + OperandList.push_back(OperandInfo(Rec, Ty, DI->getArgName(i), + PrintMethod, MIOperandNo)); + MIOperandNo += NumOps; } else { throw "Illegal operand for the '" + R->getName() + "' instruction!"; } Index: llvm/utils/TableGen/CodeGenInstruction.h diff -u llvm/utils/TableGen/CodeGenInstruction.h:1.2 llvm/utils/TableGen/CodeGenInstruction.h:1.3 --- llvm/utils/TableGen/CodeGenInstruction.h:1.2 Sun Aug 1 02:42:39 2004 +++ llvm/utils/TableGen/CodeGenInstruction.h Tue Aug 10 21:22:39 2004 @@ -31,15 +31,35 @@ /// instruction. std::string AsmString; - /// OperandInfo - For each operand declared in the OperandList of the - /// instruction, keep track of its record (which specifies the class of the - /// operand), its type, and the name given to the operand, if any. + /// OperandInfo - The information we keep track of for each operand in the + /// operand list for a tablegen instruction. struct OperandInfo { + /// Rec - The definition this operand is declared as. Record *Rec; + + /// Ty - The MachineValueType of the operand. + /// MVT::ValueType Ty; + + /// Name - If this operand was assigned a symbolic name, this is it, + /// otherwise, it's empty. std::string Name; - OperandInfo(Record *R, MVT::ValueType T, const std::string &N) - : Rec(R), Ty(T), Name(N) {} + + /// PrinterMethodName - The method used to print operands of this type in + /// the asmprinter. + std::string PrinterMethodName; + + /// MIOperandNo - Currently (this is meant to be phased out), some logical + /// operands correspond to multiple MachineInstr operands. In the X86 + /// target for example, one address operand is represented as 4 + /// MachineOperands. Because of this, the operand number in the + /// OperandList may not match the MachineInstr operand num. Until it + /// does, this contains the MI operand index of this operand. + unsigned MIOperandNo; + + OperandInfo(Record *R, MVT::ValueType T, const std::string &N, + const std::string &PMN, unsigned MION) + : Rec(R), Ty(T), Name(N), PrinterMethodName(PMN), MIOperandNo(MION) {} }; /// OperandList - The list of declared operands, along with their declared From lattner at cs.uiuc.edu Tue Aug 10 21:25:11 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 21:25:11 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td X86AsmPrinter.cpp Message-ID: <200408110225.VAA06953@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.93 -> 1.94 X86AsmPrinter.cpp updated: 1.111 -> 1.112 --- Log message: Convert asmprinter to new style of instruction printer Start asmprintergen'ifying machine instrs with memory operands. --- Diffs of the changes: (+50 -9) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.93 llvm/lib/Target/X86/X86InstrInfo.td:1.94 --- llvm/lib/Target/X86/X86InstrInfo.td:1.93 Tue Aug 10 16:21:30 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Tue Aug 10 21:25:00 2004 @@ -13,6 +13,24 @@ // //===----------------------------------------------------------------------===// +// *mem - Operand definitions for the funky X86 addressing mode operands. +// +def i8mem : Operand { + let NumMIOperands = 4; + let PrintMethod = "printMemoryOperand"; +} + +def i16mem : Operand { + let NumMIOperands = 4; + let PrintMethod = "printMemoryOperand"; +} + +def i32mem : Operand { + let NumMIOperands = 4; + let PrintMethod = "printMemoryOperand"; +} + + // Format specifies the encoding used by the instruction. This is part of the // ad-hoc solution used to emit machine instruction encodings by our machine // code emitter. @@ -219,7 +237,8 @@ def XCHG32rr : I<0x87, MRMDestReg, // xchg R32, R32 (ops R32:$src1, R32:$src2), "xchg $src1, $src2">; -def XCHG8mr : Im8 <"xchg", 0x86, MRMDestMem>; // xchg [mem8], R8 +def XCHG8mr : Im8 <"", 0x86, MRMDestMem>, // xchg [mem8], R8 + II<(ops i8mem:$src1, R8:$src2), "xchg $src1, $src2">; 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] @@ -289,13 +308,19 @@ def MOV16mi : Im16i16<"mov", 0xC7, MRM0m >, OpSize; // [mem16] = imm16 def MOV32mi : Im32i32<"mov", 0xC7, MRM0m >; // [mem32] = imm32 -def MOV8rm : Im8 <"mov", 0x8A, MRMSrcMem>; // R8 = [mem8] -def MOV16rm : Im16 <"mov", 0x8B, MRMSrcMem>, OpSize; // R16 = [mem16] -def MOV32rm : Im32 <"mov", 0x8B, MRMSrcMem>; // R32 = [mem32] - -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 +def MOV8rm : Im8 <"", 0x8A, MRMSrcMem>, // R8 = [mem8] + II<(ops R8 :$dst, i8mem :$src), "mov $dst, $src">; +def MOV16rm : Im16<"", 0x8B, MRMSrcMem>, OpSize, // R16 = [mem16] + II<(ops R16:$dst, i16mem:$src), "mov $dst, $src">; +def MOV32rm : Im32<"", 0x8B, MRMSrcMem>, // R32 = [mem32] + II<(ops R32:$dst, i32mem:$src), "mov $dst, $src">; + +def MOV8mr : Im8 <"", 0x88, MRMDestMem>, // [mem8] = R8 + II<(ops i8mem :$dst, R8 :$src), "mov $dst, $src">; +def MOV16mr : Im16<"", 0x89, MRMDestMem>, OpSize, // [mem16] = R16 + II<(ops i16mem:$dst, R16:$src), "mov $dst, $src">; +def MOV32mr : Im32<"", 0x89, MRMDestMem>, // [mem32] = R32 + II<(ops i32mem:$dst, R32:$src), "mov $dst, $src">; //===----------------------------------------------------------------------===// // Fixed-Register Multiplication and Division Instructions... Index: llvm/lib/Target/X86/X86AsmPrinter.cpp diff -u llvm/lib/Target/X86/X86AsmPrinter.cpp:1.111 llvm/lib/Target/X86/X86AsmPrinter.cpp:1.112 --- llvm/lib/Target/X86/X86AsmPrinter.cpp:1.111 Wed Aug 4 03:37:52 2004 +++ llvm/lib/Target/X86/X86AsmPrinter.cpp Tue Aug 10 21:25:00 2004 @@ -105,7 +105,8 @@ bool printInstruction(const MachineInstr *MI); // This method is used by the tablegen'erated instruction printer. - void printOperand(const MachineOperand &MO, MVT::ValueType VT) { + void printOperand(const MachineInstr *MI, unsigned OpNo, MVT::ValueType VT) { + const MachineOperand &MO = MI->getOperand(OpNo); if (MO.getType() == MachineOperand::MO_MachineRegister) { assert(MRegisterInfo::isPhysicalRegister(MO.getReg())&&"Not physref??"); // Bug Workaround: See note in Printer::doInitialization about %. @@ -115,6 +116,21 @@ } } + void printMemoryOperand(const MachineInstr *MI, unsigned OpNo, + MVT::ValueType VT) { + switch (VT) { + default: assert(0 && "Unknown arg size!"); + case MVT::i8: O << "BYTE PTR "; break; + case MVT::i16: O << "WORD PTR "; break; + case MVT::i32: + case MVT::f32: O << "DWORD PTR "; break; + case MVT::i64: + case MVT::f64: O << "QWORD PTR "; break; + case MVT::f80: O << "XWORD PTR "; break; + } + printMemReference(MI, OpNo); + } + bool printImplUsesAfter(const TargetInstrDescriptor &Desc, const bool LC); void printMachineInstruction(const MachineInstr *MI); void printOp(const MachineOperand &MO, bool elideOffsetKeyword = false); From lattner at cs.uiuc.edu Tue Aug 10 21:26:49 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 21:26:49 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86CodeEmitter.cpp Message-ID: <200408110226.VAA06982@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86CodeEmitter.cpp updated: 1.62 -> 1.63 --- Log message: Remove dead method --- Diffs of the changes: (+0 -13) Index: llvm/lib/Target/X86/X86CodeEmitter.cpp diff -u llvm/lib/Target/X86/X86CodeEmitter.cpp:1.62 llvm/lib/Target/X86/X86CodeEmitter.cpp:1.63 --- llvm/lib/Target/X86/X86CodeEmitter.cpp:1.62 Sat Jul 17 15:26:14 2004 +++ llvm/lib/Target/X86/X86CodeEmitter.cpp Tue Aug 10 21:26:39 2004 @@ -472,19 +472,6 @@ } } -static unsigned sizeOfPtr(const TargetInstrDescriptor &Desc) { - 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; - } -} - void Emitter::emitInstruction(const MachineInstr &MI) { NumEmitted++; // Keep track of the # of mi's emitted From natebegeman at mac.com Tue Aug 10 22:31:05 2004 From: natebegeman at mac.com (Nate Begeman) Date: Tue, 10 Aug 2004 22:31:05 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp Message-ID: <200408110331.WAA26033@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC32ISelSimple.cpp updated: 1.57 -> 1.58 --- Log message: Fix 255.vortex by using getClassB instead of getClass --- Diffs of the changes: (+1 -2) Index: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp diff -u llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.57 llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.58 --- llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.57 Tue Aug 10 19:09:42 2004 +++ llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp Tue Aug 10 22:30:55 2004 @@ -605,7 +605,6 @@ } return; } - std::cerr << "Unhandled integer constant!\n"; abort(); } else if (ConstantFP *CFP = dyn_cast(C)) { @@ -1243,7 +1242,7 @@ BuildMI(BB, PPC::PHI, 4, DestReg).addReg(FalseValue) .addMBB(copy0MBB).addReg(TrueValue).addMBB(copy1MBB); // For a register pair representing a long value, define the second reg - if (getClass(TrueVal->getType()) == cLong) + if (getClassB(TrueVal->getType()) == cLong) BuildMI(BB, PPC::LI, 1, DestReg+1).addImm(0); return; } From lattner at cs.uiuc.edu Tue Aug 10 23:08:48 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 23:08:48 -0500 Subject: [llvm-commits] CVS: llvm/utils/TableGen/AsmWriterEmitter.cpp Message-ID: <200408110408.XAA17340@apoc.cs.uiuc.edu> Changes in directory llvm/utils/TableGen: AsmWriterEmitter.cpp updated: 1.4 -> 1.5 --- Log message: Fix minor bug in previous checkin --- Diffs of the changes: (+5 -4) Index: llvm/utils/TableGen/AsmWriterEmitter.cpp diff -u llvm/utils/TableGen/AsmWriterEmitter.cpp:1.4 llvm/utils/TableGen/AsmWriterEmitter.cpp:1.5 --- llvm/utils/TableGen/AsmWriterEmitter.cpp:1.4 Tue Aug 10 21:23:23 2004 +++ llvm/utils/TableGen/AsmWriterEmitter.cpp Tue Aug 10 23:08:36 2004 @@ -75,15 +75,16 @@ // If this is a two-address instruction and we are not accessing the // 0th operand, remove an operand. - if (I->second.isTwoAddress && OpNo != 0) { - if (OpNo == 1) + unsigned MIOp = I->second.OperandList[OpNo].MIOperandNo; + if (I->second.isTwoAddress && MIOp != 0) { + if (MIOp == 1) throw "Should refer to operand #0 instead of #1 for two-address" " instruction '" + I->first + "'!"; - --OpNo; + --MIOp; } O << "; " << I->second.OperandList[OpNo].PrinterMethodName - << "(MI, " << I->second.OperandList[OpNo].MIOperandNo << ", MVT::" + << "(MI, " << MIOp << ", MVT::" << getName(I->second.OperandList[OpNo].Ty) << "); O "; LastEmitted = VarEnd; } From lattner at cs.uiuc.edu Tue Aug 10 23:31:12 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Tue, 10 Aug 2004 23:31:12 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200408110431.XAA18982@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.94 -> 1.95 --- Log message: Get rid of the Im8, Im16, Im32 classes, converting more instructions over to asmprintergeneration --- Diffs of the changes: (+301 -225) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.94 llvm/lib/Target/X86/X86InstrInfo.td:1.95 --- llvm/lib/Target/X86/X86InstrInfo.td:1.94 Tue Aug 10 21:25:00 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Tue Aug 10 23:31:00 2004 @@ -146,11 +146,6 @@ class I o, Format f, dag ops, string asm> : X86Inst<"", o, f, NoMem, NoImm>, II; -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<"", o, f, NoMem, i>; class Ii8 o, Format f, dag ops, string asm> : Ii, II; class Ii16 o, Format f, dag ops, string asm> : Ii, II; @@ -214,7 +209,7 @@ let Defs = [EAX, ECX, EDX, FP0, FP1, FP2, FP3, FP4, FP5, FP6] in { def CALLpcrel32 : X86Inst<"call", 0xE8, RawFrm, NoMem, NoImm>; // FIXME: 'call' doesn't allow 'OFFSET' def CALL32r : I<0xFF, MRM2r, (ops R32:$dst), "call $dst">; - def CALL32m : Im32<"call", 0xFF, MRM2m>; + def CALL32m : I<0xFF, MRM2m, (ops i32mem:$dst), "call $dst">; } @@ -237,16 +232,15 @@ def XCHG32rr : I<0x87, MRMDestReg, // xchg R32, R32 (ops R32:$src1, R32:$src2), "xchg $src1, $src2">; -def XCHG8mr : Im8 <"", 0x86, MRMDestMem>, // xchg [mem8], R8 - II<(ops i8mem:$src1, R8:$src2), "xchg $src1, $src2">; -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 XCHG8mr : I<0x86, MRMDestMem, (ops i8mem:$src1, R8:$src2), "xchg $src1, $src2">; +def XCHG16mr : I<0x87, MRMDestMem, (ops i16mem:$src1, R16:$src2), "xchg $src1, $src2">, OpSize; +def XCHG32mr : I<0x87, MRMDestMem, (ops i32mem:$src1, R32:$src2), "xchg $src1, $src2">; +def XCHG8rm : I<0x86, MRMSrcMem , (ops R8:$src1, i8mem:$src2), "xchg $src1, $src2">; +def XCHG16rm : I<0x87, MRMSrcMem , (ops R16:$src1, i16mem:$src2), "xchg $src1, $src2">, OpSize; +def XCHG32rm : I<0x87, MRMSrcMem , (ops R32:$src1, i32mem:$src2), "xchg $src1, $src2">; -def LEA16r : Im32<"lea", 0x8D, MRMSrcMem>, OpSize; // R16 = lea [mem] -def LEA32r : Im32<"lea", 0x8D, MRMSrcMem>; // R32 = lea [mem] +def LEA16r : I<0x8D, MRMSrcMem, (ops R16:$dst, i32mem:$src), "lea $dst, $src">, OpSize; +def LEA32r : I<0x8D, MRMSrcMem, (ops R32:$dst, i32mem:$src), "lea $dst, $src">; def REP_MOVSB : I<0xA4, RawFrm, (ops), "rep movsb">, @@ -304,23 +298,17 @@ def MOV8ri : Ii8 <0xB0, AddRegFrm, (ops R8 :$dst, i8imm :$src), "mov $dst, $src">; def MOV16ri : Ii16<0xB8, AddRegFrm, (ops R16:$dst, i16imm:$src), "mov $dst, $src">, OpSize; def MOV32ri : Ii32<0xB8, AddRegFrm, (ops R32:$dst, i32imm:$src), "mov $dst, $src">; -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 MOV8rm : Im8 <"", 0x8A, MRMSrcMem>, // R8 = [mem8] - II<(ops R8 :$dst, i8mem :$src), "mov $dst, $src">; -def MOV16rm : Im16<"", 0x8B, MRMSrcMem>, OpSize, // R16 = [mem16] - II<(ops R16:$dst, i16mem:$src), "mov $dst, $src">; -def MOV32rm : Im32<"", 0x8B, MRMSrcMem>, // R32 = [mem32] - II<(ops R32:$dst, i32mem:$src), "mov $dst, $src">; - -def MOV8mr : Im8 <"", 0x88, MRMDestMem>, // [mem8] = R8 - II<(ops i8mem :$dst, R8 :$src), "mov $dst, $src">; -def MOV16mr : Im16<"", 0x89, MRMDestMem>, OpSize, // [mem16] = R16 - II<(ops i16mem:$dst, R16:$src), "mov $dst, $src">; -def MOV32mr : Im32<"", 0x89, MRMDestMem>, // [mem32] = R32 - II<(ops i32mem:$dst, R32:$src), "mov $dst, $src">; +def MOV8mi : Ii8 <0xC6, MRM0m, (ops i8mem :$dst, i8imm :$src), "mov $dst, $src">; +def MOV16mi : Ii16<0xC7, MRM0m, (ops i16mem:$dst, i16imm:$src), "mov $dst, $src">, OpSize; +def MOV32mi : Ii32<0xC7, MRM0m, (ops i32mem:$dst, i32imm:$src), "mov $dst, $src">; + +def MOV8rm : I<0x8A, MRMSrcMem, (ops R8 :$dst, i8mem :$src), "mov $dst, $src">; +def MOV16rm : I<0x8B, MRMSrcMem, (ops R16:$dst, i16mem:$src), "mov $dst, $src">, OpSize; +def MOV32rm : I<0x8B, MRMSrcMem, (ops R32:$dst, i32mem:$src), "mov $dst, $src">; + +def MOV8mr : I<0x88, MRMDestMem, (ops i8mem :$dst, R8 :$src), "mov $dst, $src">; +def MOV16mr : I<0x89, MRMDestMem, (ops i16mem:$dst, R16:$src), "mov $dst, $src">, OpSize; +def MOV32mr : I<0x89, MRMDestMem, (ops i32mem:$dst, R32:$src), "mov $dst, $src">; //===----------------------------------------------------------------------===// // Fixed-Register Multiplication and Division Instructions... @@ -333,9 +321,12 @@ Imp<[AX],[AX,DX]>, OpSize; // AX,DX = AX*R16 def MUL32r : I<0xF7, MRM4r, (ops R32:$src), "mul $src">, 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] +def MUL8m : I<0xF6, MRM4m, (ops i8mem :$src), + "mul $src">, Imp<[AL],[AX]>; // AL,AH = AL*[mem8] +def MUL16m : I<0xF7, MRM4m, (ops i16mem:$src), + "mul $src">, Imp<[AX],[AX,DX]>, OpSize; // AX,DX = AX*[mem16] +def MUL32m : I<0xF7, MRM4m, (ops i32mem:$src), + "mul $src">, Imp<[EAX],[EAX,EDX]>; // EAX,EDX = EAX*[mem32] // unsigned division/remainder def DIV8r : I<0xF6, MRM6r, (ops R8:$src), "div $src">, @@ -344,9 +335,9 @@ Imp<[AX,DX],[AX,DX]>, OpSize; // DX:AX/r16 = AX,DX def DIV32r : I<0xF7, MRM6r, (ops R32:$src), "div $src">, 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 +def DIV8m : I<0xF6, MRM6m, (ops i8mem:$src), "div $src">, Imp<[AX],[AX]>; // AX/[mem8] = AL,AH +def DIV16m : I<0xF7, MRM6m, (ops i16mem:$src), "div $src">, Imp<[AX,DX],[AX,DX]>, OpSize; // DX:AX/[mem16] = AX,DX +def DIV32m : I<0xF7, MRM6m, (ops i32mem:$src), "div $src">, Imp<[EAX,EDX],[EAX,EDX]>; // EDX:EAX/[mem32] = EAX,EDX // Signed division/remainder. def IDIV8r : I<0xF6, MRM7r, (ops R8:$src), "idiv $src">, @@ -355,9 +346,9 @@ Imp<[AX,DX],[AX,DX]>, OpSize; // DX:AX/r16 = AX,DX def IDIV32r: I<0xF7, MRM7r, (ops R32:$src), "idiv $src">, 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 +def IDIV8m : I<0xF6, MRM7m, (ops i8mem:$src), "idiv $src">, Imp<[AX],[AX]>; // AX/[mem8] = AL,AH +def IDIV16m: I<0xF7, MRM7m, (ops i16mem:$src), "idiv $src">, Imp<[AX,DX],[AX,DX]>, OpSize; // DX:AX/[mem16] = AX,DX +def IDIV32m: I<0xF7, MRM7m, (ops i32mem:$src), "idiv $src">, Imp<[EAX,EDX],[EAX,EDX]>; // EDX:EAX/[mem32] = EAX,EDX // Sign-extenders for division. def CBW : I<0x98, RawFrm, (ops), "cbw">, Imp<[AL],[AH]>; // AX = signext(AL) @@ -373,127 +364,164 @@ // Conditional moves def CMOVB16rr : I<0x42, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "cmovb $dst, $src2">, TB, OpSize; // if , TB, OpSize; // if , TB, OpSize; // if , TB; // if , TB; // if , TB; // if , TB, OpSize; // if >=u, R16 = R16 -def CMOVAE16rm: Im16<"cmovae", 0x43, MRMSrcMem>, TB, OpSize; // if >=u, R16 = [mem16] +def CMOVAE16rm: I<0x43, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), + "cmovae $dst, $src2">, TB, OpSize; // if >=u, R16 = [mem16] def CMOVAE32rr: I<0x43, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "cmovae $dst, $src2">, TB; // if >=u, R32 = R32 -def CMOVAE32rm: Im32<"cmovae", 0x43, MRMSrcMem>, TB; // if >=u, R32 = [mem32] +def CMOVAE32rm: I<0x43, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), + "cmovae $dst, $src2">, TB; // if >=u, R32 = [mem32] def CMOVE16rr : I<0x44, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "cmove $dst, $src2">, TB, OpSize; // if ==, R16 = R16 -def CMOVE16rm : Im16<"cmove", 0x44, MRMSrcMem>, TB, OpSize; // if ==, R16 = [mem16] +def CMOVE16rm : I<0x44, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), + "cmove $dst, $src2">, TB, OpSize; // if ==, R16 = [mem16] def CMOVE32rr : I<0x44, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "cmove $dst, $src2">, TB; // if ==, R32 = R32 -def CMOVE32rm : Im32<"cmove", 0x44, MRMSrcMem>, TB; // if ==, R32 = [mem32] +def CMOVE32rm : I<0x44, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), + "cmove $dst, $src2">, TB; // if ==, R32 = [mem32] def CMOVNE16rr: I<0x45, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "cmovne $dst, $src2">, TB, OpSize; // if !=, R16 = R16 -def CMOVNE16rm: Im16<"cmovne",0x45, MRMSrcMem>, TB, OpSize; // if !=, R16 = [mem16] +def CMOVNE16rm: I<0x45, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), + "cmovne $dst, $src2">, TB, OpSize; // if !=, R16 = [mem16] def CMOVNE32rr: I<0x45, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "cmovne $dst, $src2">, TB; // if !=, R32 = R32 -def CMOVNE32rm: Im32<"cmovne",0x45, MRMSrcMem>, TB; // if !=, R32 = [mem32] +def CMOVNE32rm: I<0x45, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), + "cmovne $dst, $src2">, TB; // if !=, R32 = [mem32] def CMOVBE16rr: I<0x46, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "cmovbe $dst, $src2">, TB, OpSize; // if <=u, R16 = R16 -def CMOVBE16rm: Im16<"cmovbe",0x46, MRMSrcMem>, TB, OpSize; // if <=u, R16 = [mem16] +def CMOVBE16rm: I<0x46, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), + "cmovbe $dst, $src2">, TB, OpSize; // if <=u, R16 = [mem16] def CMOVBE32rr: I<0x46, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "cmovbe $dst, $src2">, TB; // if <=u, R32 = R32 -def CMOVBE32rm: Im32<"cmovbe",0x46, MRMSrcMem>, TB; // if <=u, R32 = [mem32] +def CMOVBE32rm: I<0x46, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), + "cmovbe $dst, $src2">, TB; // if <=u, R32 = [mem32] def CMOVA16rr : I<0x47, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "cmova $dst, $src2">, TB, OpSize; // if >u, R16 = R16 -def CMOVA16rm : Im16<"cmova", 0x47, MRMSrcMem>, TB, OpSize; // if >u, R16 = [mem16] +def CMOVA16rm : I<0x47, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), + "cmova $dst, $src2">, TB, OpSize; // if >u, R16 = [mem16] def CMOVA32rr : I<0x47, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "cmova $dst, $src2">, TB; // if >u, R32 = R32 -def CMOVA32rm : Im32<"cmova", 0x47, MRMSrcMem>, TB; // if >u, R32 = [mem32] +def CMOVA32rm : I<0x47, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), + "cmova $dst, $src2">, TB; // if >u, R32 = [mem32] def CMOVS16rr : I<0x48, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "cmovs $dst, $src2">, TB, OpSize; // if signed, R16 = R16 -def CMOVS16rm : Im16<"cmovs", 0x48, MRMSrcMem>, TB, OpSize; // if signed, R16 = [mem16] +def CMOVS16rm : I<0x48, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), + "cmovs $dst, $src2">, TB, OpSize; // if signed, R16 = [mem16] def CMOVS32rr : I<0x48, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "cmovs $dst, $src2">, TB; // if signed, R32 = R32 -def CMOVS32rm : Im32<"cmovs", 0x48, MRMSrcMem>, TB; // if signed, R32 = [mem32] +def CMOVS32rm : I<0x48, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), + "cmovs $dst, $src2">, TB; // if signed, R32 = [mem32] def CMOVNS16rr: I<0x49, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "cmovns $dst, $src2">, TB, OpSize; // if !signed, R16 = R16 -def CMOVNS16rm: Im16<"cmovns",0x49, MRMSrcMem>, TB, OpSize; // if !signed, R16 = [mem16] +def CMOVNS16rm: I<0x49, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), + "cmovns $dst, $src2">, TB, OpSize; // if !signed, R16 = [mem16] def CMOVNS32rr: I<0x49, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "cmovns $dst, $src2">, TB; // if !signed, R32 = R32 -def CMOVNS32rm: Im32<"cmovns",0x49, MRMSrcMem>, TB; // if !signed, R32 = [mem32] +def CMOVNS32rm: I<0x49, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), + "cmovns $dst, $src2">, TB; // if !signed, R32 = [mem32] def CMOVL16rr : I<0x4C, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "cmovl $dst, $src2">, TB, OpSize; // if , TB, OpSize; // if , TB, OpSize; // if , TB; // if , TB; // if , TB; // if , TB, OpSize; // if >=s, R16 = R16 -def CMOVGE16rm: Im16<"cmovge",0x4D, MRMSrcMem>, TB, OpSize; // if >=s, R16 = [mem16] +def CMOVGE16rm: I<0x4D, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), + "cmovge $dst, $src2">, TB, OpSize; // if >=s, R16 = [mem16] def CMOVGE32rr: I<0x4D, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "cmovge $dst, $src2">, TB; // if >=s, R32 = R32 -def CMOVGE32rm: Im32<"cmovge",0x4D, MRMSrcMem>, TB; // if >=s, R32 = [mem32] +def CMOVGE32rm: I<0x4D, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), + "cmovge $dst, $src2">, TB; // if >=s, R32 = [mem32] def CMOVLE16rr: I<0x4E, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "cmovle $dst, $src2">, TB, OpSize; // if <=s, R16 = R16 -def CMOVLE16rm: Im16<"cmovle",0x4E, MRMSrcMem>, TB, OpSize; // if <=s, R16 = [mem16] +def CMOVLE16rm: I<0x4E, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), + "cmovle $dst, $src2">, TB, OpSize; // if <=s, R16 = [mem16] def CMOVLE32rr: I<0x4E, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "cmovle $dst, $src2">, TB; // if <=s, R32 = R32 -def CMOVLE32rm: Im32<"cmovle",0x4E, MRMSrcMem>, TB; // if <=s, R32 = [mem32] +def CMOVLE32rm: I<0x4E, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), + "cmovle $dst, $src2">, TB; // if <=s, R32 = [mem32] def CMOVG16rr : I<0x4F, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "cmovg $dst, $src2">, TB, OpSize; // if >s, R16 = R16 -def CMOVG16rm : Im16<"cmovg", 0x4F, MRMSrcMem>, TB, OpSize; // if >s, R16 = [mem16] +def CMOVG16rm : I<0x4F, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), + "cmovg $dst, $src2">, TB, OpSize; // if >s, R16 = [mem16] def CMOVG32rr : I<0x4F, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "cmovg $dst, $src2">, TB; // if >s, R32 = R32 -def CMOVG32rm : Im32<"cmovg", 0x4F, MRMSrcMem>, TB; // if >s, R32 = [mem32] +def CMOVG32rm : I<0x4F, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), + "cmovg $dst, $src2">, TB; // if >s, R32 = [mem32] // unary instructions def NEG8r : I<0xF6, MRM3r, (ops R8 :$dst, R8 :$src), "neg $dst">; def NEG16r : I<0xF7, MRM3r, (ops R16:$dst, R16:$src), "neg $dst">, OpSize; def NEG32r : I<0xF7, MRM3r, (ops R32:$dst, R32:$src), "neg $dst">; -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] +let isTwoAddress = 0 in { + def NEG8m : I<0xF6, MRM3m, (ops i8mem :$dst), "neg $dst">; + def NEG16m : I<0xF7, MRM3m, (ops i16mem:$dst), "neg $dst">, OpSize; + def NEG32m : I<0xF7, MRM3m, (ops i32mem:$dst), "neg $dst">; +} def NOT8r : I<0xF6, MRM2r, (ops R8 :$dst, R8 :$src), "not $dst">; def NOT16r : I<0xF7, MRM2r, (ops R16:$dst, R16:$src), "not $dst">, OpSize; def NOT32r : I<0xF7, MRM2r, (ops R32:$dst, R32:$src), "not $dst">; -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] +let isTwoAddress = 0 in { + def NOT8m : I<0xF6, MRM2m, (ops i8mem :$dst), "not $dst">; + def NOT16m : I<0xF7, MRM2m, (ops i16mem:$dst), "not $dst">, OpSize; + def NOT32m : I<0xF7, MRM2m, (ops i32mem:$dst), "not $dst">; +} def INC8r : I<0xFE, MRM0r, (ops R8 :$dst, R8 :$src), "inc $dst">; def INC16r : I<0xFF, MRM0r, (ops R16:$dst, R16:$src), "inc $dst">, OpSize; def INC32r : I<0xFF, MRM0r, (ops R32:$dst, R32:$src), "inc $dst">; -def INC8m : Im8 <"inc", 0xFE, MRM0m>; // ++R8 -def INC16m : Im16<"inc", 0xFF, MRM0m>, OpSize; // ++R16 -def INC32m : Im32<"inc", 0xFF, MRM0m>; // ++R32 +let isTwoAddress = 0 in { + def INC8m : I<0xFE, MRM0m, (ops i8mem :$dst), "inc $dst">; + def INC16m : I<0xFF, MRM0m, (ops i16mem:$dst), "inc $dst">, OpSize; + def INC32m : I<0xFF, MRM0m, (ops i32mem:$dst), "inc $dst">; +} def DEC8r : I<0xFE, MRM1r, (ops R8 :$dst, R8 :$src), "dec $dst">; def DEC16r : I<0xFF, MRM1r, (ops R16:$dst, R16:$src), "dec $dst">, OpSize; def DEC32r : I<0xFF, MRM1r, (ops R32:$dst, R32:$src), "dec $dst">; -def DEC8m : Im8 <"dec", 0xFE, MRM1m>; // --[mem8] -def DEC16m : Im16<"dec", 0xFF, MRM1m>, OpSize; // --[mem16] -def DEC32m : Im32<"dec", 0xFF, MRM1m>; // --[mem32] + +let isTwoAddress = 0 in { + def DEC8m : I<0xFE, MRM1m, (ops i8mem :$dst), "dec $dst">; + def DEC16m : I<0xFF, MRM1m, (ops i16mem:$dst), "dec $dst">, OpSize; + def DEC32m : I<0xFF, MRM1m, (ops i32mem:$dst), "dec $dst">; +} // Logical operators... def AND8rr : I<0x20, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "and $dst, $src2">; def AND16rr : I<0x21, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "and $dst, $src2">, OpSize; def AND32rr : I<0x21, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "and $dst, $src2">; -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] + +let isTwoAddress = 0 in { + def AND8mr : I<0x20, MRMDestMem, (ops i8mem :$dst, R8 :$src), "and $dst, $src">; + def AND16mr : I<0x21, MRMDestMem, (ops i16mem:$dst, R16:$src), "and $dst, $src">, OpSize; + def AND32mr : I<0x21, MRMDestMem, (ops i32mem:$dst, R32:$src), "and $dst, $src">; +} + +def AND8rm : I<0x22, MRMSrcMem , (ops R8 :$dst, R8 :$src1, i8mem :$src2), "and $dst, $src2">; +def AND16rm : I<0x23, MRMSrcMem , (ops R16:$dst, R16:$src1, i16mem:$src2), "and $dst, $src2">, OpSize; +def AND32rm : I<0x23, MRMSrcMem , (ops R32:$dst, R32:$src1, i32mem:$src2), "and $dst, $src2">; def AND8ri : Ii8 <0x80, MRM4r, (ops R8 :$dst, R8 :$src1, i8imm :$src2), "and $dst, $src2">; @@ -519,12 +547,20 @@ "or $dst, $src2">, OpSize; def OR32rr : I<0x09, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "or $dst, $src2">; -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] +let isTwoAddress = 0 in { + def OR8mr : I<0x08, MRMDestMem, (ops i8mem:$dst, R8:$src), + "or $dst, $src">; + def OR16mr : I<0x09, MRMDestMem, (ops i16mem:$dst, R16:$src), + "or $dst, $src">, OpSize; + def OR32mr : I<0x09, MRMDestMem, (ops i32mem:$dst, R32:$src), + "or $dst, $src">; +} +def OR8rm : I<0x0A, MRMSrcMem , (ops R8 :$dst, R8 :$src1, i8mem :$src2), + "or $dst, $src2">; +def OR16rm : I<0x0B, MRMSrcMem , (ops R16:$dst, R16:$src1, i16mem:$src2), + "or $dst, $src2">, OpSize; +def OR32rm : I<0x0B, MRMSrcMem , (ops R32:$dst, R32:$src1, i32mem:$src2), + "or $dst, $src2">; def OR8ri : Ii8 <0x80, MRM1r, (ops R8 :$dst, R8 :$src1, i8imm:$src2), "or $dst, $src2">; @@ -532,51 +568,60 @@ "or $dst, $src2">, OpSize; def OR32ri : Ii32<0x81, MRM1r, (ops R32:$dst, R32:$src1, i32imm:$src2), "or $dst, $src2">; -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 +let isTwoAddress = 0 in { + 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<0x83, MRM1r, (ops R8 :$dst, R8 :$src1, i8imm:$src2), "or $dst, $src2">, OpSize; def OR32ri8 : Ii8<0x83, MRM1r, (ops R32:$dst, R32:$src1, i8imm:$src2), "or $dst, $src2">; -def OR16mi8 : Im16i8<"or" , 0x83, MRM1m>, OpSize; // [mem16] |= imm8 -def OR32mi8 : Im32i8<"or" , 0x83, MRM1m>; // [mem32] |= imm8 +let isTwoAddress = 0 in { + def OR16mi8 : Im16i8<"or" , 0x83, MRM1m>, OpSize; // [mem16] |= imm8 + def OR32mi8 : Im32i8<"or" , 0x83, MRM1m>; // [mem32] |= imm8 +} def XOR8rr : I<0x30, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "xor $dst, $src2">; def XOR16rr : I<0x31, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "xor $dst, $src2">, OpSize; def XOR32rr : I<0x31, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "xor $dst, $src2">; -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] +let isTwoAddress = 0 in { + def XOR8mr : I<0x30, MRMDestMem, (ops i8mem :$dst, R8 :$src), "xor $dst, $src">; + def XOR16mr: I<0x31, MRMDestMem, (ops i16mem:$dst, R16:$src), "xor $dst, $src">, OpSize; + def XOR32mr: I<0x31, MRMDestMem, (ops i32mem:$dst, R32:$src), "xor $dst, $src">; +} +def XOR8rm : I<0x32, MRMSrcMem , (ops R8 :$dst, R8:$src1, i8mem :$src2), "xor $dst, $src2">; +def XOR16rm : I<0x33, MRMSrcMem , (ops R16:$dst, R8:$src1, i16mem:$src2), "xor $dst, $src2">, OpSize; +def XOR32rm : I<0x33, MRMSrcMem , (ops R32:$dst, R8:$src1, i32mem:$src2), "xor $dst, $src2">; def XOR8ri : Ii8 <0x80, MRM6r, (ops R8:$dst, R8:$src1, i8imm:$src2), "xor $dst, $src2">; def XOR16ri : Ii16 <0x81, MRM6r, (ops R16:$dst, R16:$src1, i16imm:$src2), "xor $dst, $src2">, OpSize; def XOR32ri : Ii32 <0x81, MRM6r, (ops R32:$dst, R32:$src1, i32imm:$src2), "xor $dst, $src2">; -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 - +let isTwoAddress = 0 in { + 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<0x83, MRM6r, (ops R16:$dst, R16:$src1, i8imm:$src2), "xor $dst, $src2">, OpSize; def XOR32ri8 : Ii8<0x83, MRM6r, (ops R32:$dst, R32:$src1, i8imm:$src2), "xor $dst, $src2">; -def XOR16mi8 : Im16i8<"xor", 0x83, MRM6m >, OpSize; // [mem16] ^= imm8 -def XOR32mi8 : Im32i8<"xor", 0x83, MRM6m >; // [mem32] ^= imm8 +let isTwoAddress = 0 in { + def XOR16mi8 : Im16i8<"xor", 0x83, MRM6m >, OpSize; // [mem16] ^= imm8 + def XOR32mi8 : Im32i8<"xor", 0x83, MRM6m >; // [mem32] ^= imm8 +} // Shift instructions // FIXME: provide shorter instructions when imm8 == 1 -let Uses = [CL], printImplicitUsesAfter = 1 in { - def SHL8rCL : I<0xD2, MRM4r, (ops R8 :$dst, R8 :$src), "shl $dst, %CL">; - def SHL16rCL : I<0xD3, MRM4r, (ops R16:$dst, R16:$src), "shl $dst, %CL">, OpSize; - def SHL32rCL : I<0xD3, MRM4r, (ops R32:$dst, R32:$src), "shl $dst, %CL">; - def SHL8mCL : Im8 <"shl", 0xD2, MRM4m > ; // [mem8] <<= cl - def SHL16mCL : Im16 <"shl", 0xD3, MRM4m >, OpSize; // [mem16] <<= cl - def SHL32mCL : Im32 <"shl", 0xD3, MRM4m > ; // [mem32] <<= cl +def SHL8rCL : I<0xD2, MRM4r, (ops R8 :$dst, R8 :$src), "shl $dst, %CL">, Imp<[CL],[]>; +def SHL16rCL : I<0xD3, MRM4r, (ops R16:$dst, R16:$src), "shl $dst, %CL">, Imp<[CL],[]>, OpSize; +def SHL32rCL : I<0xD3, MRM4r, (ops R32:$dst, R32:$src), "shl $dst, %CL">, Imp<[CL],[]>; +let isTwoAddress = 0 in { + def SHL8mCL : I<0xD2, MRM4m, (ops i8mem :$dst), "shl $dst, %CL">, Imp<[CL],[]>; + def SHL16mCL : I<0xD3, MRM4m, (ops i16mem:$dst), "shl $dst, %CL">, Imp<[CL],[]>, OpSize; + def SHL32mCL : I<0xD3, MRM4m, (ops i32mem:$dst), "shl $dst, %CL">, Imp<[CL],[]>; } def SHL8ri : Ii8<0xC0, MRM4r, (ops R8 :$dst, R8 :$src1, i8imm:$src2), @@ -589,29 +634,31 @@ def SHL16mi : Im16i8<"shl", 0xC1, MRM4m >, OpSize; // [mem16] <<= imm8 def SHL32mi : Im32i8<"shl", 0xC1, MRM4m >; // [mem32] <<= imm8 -let Uses = [CL], printImplicitUsesAfter = 1 in { - def SHR8rCL : I<0xD2, MRM5r, (ops R8 :$dst, R8 :$src), "shr $dst, %CL">; - def SHR16rCL : I<0xD3, MRM5r, (ops R16:$dst, R16:$src), "shr $dst, %CL">, OpSize; - def SHR32rCL : I<0xD3, MRM5r, (ops R32:$dst, R32:$src), "shr $dst, %CL">; - def SHR8mCL : Im8 <"shr", 0xD2, MRM5m > ; // [mem8] >>= cl - def SHR16mCL : Im16 <"shr", 0xD3, MRM5m >, OpSize; // [mem16] >>= cl - def SHR32mCL : Im32 <"shr", 0xD3, MRM5m > ; // [mem32] >>= cl +def SHR8rCL : I<0xD2, MRM5r, (ops R8 :$dst, R8 :$src), "shr $dst, %CL">, Imp<[CL],[]>; +def SHR16rCL : I<0xD3, MRM5r, (ops R16:$dst, R16:$src), "shr $dst, %CL">, Imp<[CL],[]>, OpSize; +def SHR32rCL : I<0xD3, MRM5r, (ops R32:$dst, R32:$src), "shr $dst, %CL">, Imp<[CL],[]>; +let isTwoAddress = 0 in { + def SHR8mCL : I<0xD2, MRM5m, (ops i8mem :$dst), "shr $dst, %CL">, Imp<[CL],[]>; + def SHR16mCL : I<0xD3, MRM5m, (ops i16mem:$dst), "shr $dst, %CL">, Imp<[CL],[]>, OpSize; + def SHR32mCL : I<0xD3, MRM5m, (ops i32mem:$dst), "shr $dst, %CL">, Imp<[CL],[]>; } def SHR8ri : Ii8 <0xC0, MRM5r, (ops R8:$dst, R8:$src1, i8imm:$src2), "shr $dst, $src2">; def SHR16ri : Ii8 <0xC1, MRM5r, (ops R16:$dst, R16:$src1, i8imm:$src2), "shr $dst, $src2">, OpSize; def SHR32ri : Ii8 <0xC1, MRM5r, (ops R32:$dst, R32:$src1, i8imm:$src2), "shr $dst, $src2">; -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 - -let Uses = [CL], printImplicitUsesAfter = 1 in { - def SAR8rCL : I<0xD2, MRM7r, (ops R8 :$dst, R8 :$src), "sar $dst, %CL">; - def SAR16rCL : I<0xD3, MRM7r, (ops R16:$dst, R16:$src), "sar $dst, %CL">, OpSize; - def SAR32rCL : I<0xD3, MRM7r, (ops R32:$dst, R32:$src), "sar $dst, %CL">; - def SAR8mCL : Im8 <"sar", 0xD2, MRM7m > ; // [mem8] >>>= cl - def SAR16mCL : Im16 <"sar", 0xD3, MRM7m >, OpSize; // [mem16] >>>= cl - def SAR32mCL : Im32 <"sar", 0xD3, MRM7m > ; // [mem32] >>>= cl +let isTwoAddress = 0 in { + def SHR8mi : Ii8 <0xC0, MRM5m, (ops i8mem :$dst, i8imm:$src), "shr $dst, $src">; + def SHR16mi : Ii8<0xC1, MRM5m, (ops i16mem:$dst, i8imm:$src), "shr $dst, $src">, OpSize; + def SHR32mi : Ii8<0xC1, MRM5m, (ops i32mem:$dst, i8imm:$src), "shr $dst, $src">; +} + +def SAR8rCL : I<0xD2, MRM7r, (ops R8 :$dst, R8 :$src), "sar $dst, %CL">, Imp<[CL],[]>; +def SAR16rCL : I<0xD3, MRM7r, (ops R16:$dst, R16:$src), "sar $dst, %CL">, Imp<[CL],[]>, OpSize; +def SAR32rCL : I<0xD3, MRM7r, (ops R32:$dst, R32:$src), "sar $dst, %CL">, Imp<[CL],[]>; +let isTwoAddress = 0 in { + def SAR8mCL : I<0xD2, MRM7m, (ops i8mem :$dst), "sar $dst, %CL">, Imp<[CL],[]>; + def SAR16mCL : I<0xD3, MRM7m, (ops i16mem:$dst), "sar $dst, %CL">, Imp<[CL],[]>, OpSize; + def SAR32mCL : I<0xD3, MRM7m, (ops i32mem:$dst), "sar $dst, %CL">, Imp<[CL],[]>; } def SAR8ri : Ii8<0xC0, MRM7r, (ops R8 :$dst, R8 :$src1, i8imm:$src2), @@ -624,63 +671,79 @@ def SAR16mi : Im16i8<"sar", 0xC1, MRM7m >, OpSize; // [mem16] >>>= imm8 def SAR32mi : Im32i8<"sar", 0xC1, MRM7m >; // [mem32] >>>= imm8 -let Uses = [CL], printImplicitUsesAfter = 1 in { - def SHLD32rrCL : I<0xA5, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), - "shld $dst, $src2, %CL">, TB; - def SHLD32mrCL : Im32 <"shld", 0xA5, MRMDestMem>, TB; // [mem32] <<= [mem32],R32 cl - def SHRD32rrCL : I<0xAD, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), - "shrd $dst, $src2, %CL">, TB; - def SHRD32mrCL : Im32 <"shrd", 0xAD, MRMDestMem>, TB; // [mem32] >>= [mem32],R32 cl +def SHLD32rrCL : I<0xA5, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), + "shld $dst, $src2, %CL">, Imp<[CL],[]>, TB; +def SHRD32rrCL : I<0xAD, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), + "shrd $dst, $src2, %CL">, Imp<[CL],[]>, TB; +def SHLD32rri8 : Ii8<0xA4, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2, i8imm:$src3), + "shld $dst, $src2, $src3">, TB; +def SHRD32rri8 : Ii8<0xAC, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2, i8imm:$src3), + "shrd $dst, $src2, $src3">, TB; + +let isTwoAddress = 0 in { + def SHLD32mrCL : I<0xA5, MRMDestMem, (ops i32mem:$dst, R32:$src2), + "shld $dst, $src2, %CL">, Imp<[CL],[]>, TB; + def SHRD32mrCL : I<0xAD, MRMDestMem, (ops i32mem:$dst, R32:$src2), + "shrd $dst, $src2, %CL">, Imp<[CL],[]>, TB; + def SHLD32mri8 : Ii8<0xA4, MRMDestMem, (ops i32mem:$dst, R32:$src2, i8imm:$src3), + "shld $dst, $src2, $src3">, TB; + def SHRD32mri8 : Ii8<0xAC, MRMDestMem, (ops i32mem:$dst, R32:$src2, i8imm:$src3), + "shrd $dst, $src2, $src3">, TB; } -def SHLD32rri8 : Ii8 <0xA4, MRMDestReg, (ops R8:$dst, R8:$src1, i8imm:$src2), - "shld $dst, $src2">, TB; -def SHLD32mri8 : Im32i8<"shld", 0xA4, MRMDestMem>, TB; // [mem32] <<= [mem32],R32 imm8 -def SHRD32rri8 : Ii8 <0xAC, MRMDestReg, (ops R16:$dst, R16:$src1, i8imm:$src2), - "shrd $dst, $src2">, TB; -def SHRD32mri8 : Im32i8<"shrd", 0xAC, MRMDestMem>, TB; // [mem32] >>= [mem32],R32 imm8 - // Arithmetic... def ADD8rr : I<0x00, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "add $dst, $src2">; def ADD16rr : I<0x01, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "add $dst, $src2">, OpSize; def ADD32rr : I<0x01, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "add $dst, $src2">; -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] +let isTwoAddress = 0 in { + def ADD8mr : I<0x00, MRMDestMem, (ops i8mem :$dst, R8 :$src2), "add $dst, $src2">; + def ADD16mr : I<0x01, MRMDestMem, (ops i16mem:$dst, R16:$src2), "add $dst, $src2">, OpSize; + def ADD32mr : I<0x01, MRMDestMem, (ops i32mem:$dst, R32:$src2), "add $dst, $src2">; +} +def ADD8rm : I<0x02, MRMSrcMem, (ops R8 :$dst, R8 :$src1, i8mem :$src2), "add $dst, $src2">; +def ADD16rm : I<0x03, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), "add $dst, $src2">, OpSize; +def ADD32rm : I<0x03, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), "add $dst, $src2">; def ADD8ri : Ii8 <0x80, MRM0r, (ops R8:$dst, R8:$src1, i8imm:$src2), "add $dst, $src2">; def ADD16ri : Ii16 <0x81, MRM0r, (ops R16:$dst, R16:$src1, i16imm:$src2), "add $dst, $src2">, OpSize; def ADD32ri : Ii32 <0x81, MRM0r, (ops R32:$dst, R32:$src1, i32imm:$src2), "add $dst, $src2">; -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 +let isTwoAddress = 0 in { + 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 <0x83, MRM0r, (ops R16:$dst, R16:$src1, i8imm:$src2), "add $dst, $src2">, OpSize; def ADD32ri8 : Ii8 <0x83, MRM0r, (ops R32:$dst, R32:$src1, i8imm:$src2), "add $dst, $src2">; -def ADD16mi8 : Im16i8<"add", 0x83, MRM0m >, OpSize; // [mem16] += I8 -def ADD32mi8 : Im32i8<"add", 0x83, MRM0m >; // [mem32] += I8 + +let isTwoAddress = 0 in { + def ADD16mi8 : Im16i8<"add", 0x83, MRM0m >, OpSize; // [mem16] += I8 + def ADD32mi8 : Im32i8<"add", 0x83, MRM0m >; // [mem32] += I8 +} def ADC32rr : I<0x11, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "adc $dst, $src2">; -def ADC32mr : Im32 <"adc", 0x11, MRMDestMem>; // [mem32] += R32+Carry -def ADC32rm : Im32 <"adc", 0x13, MRMSrcMem >; // R32 += [mem32]+Carry -def ADC32ri : Ii32 <0x81, MRM2r, (ops R32:$dst, R32:$src1, i32imm:$src2), "adc $dst, $src2">; -def ADC32ri8 : Ii8 <0x83, MRM2r, (ops R32:$dst, R32:$src1, i8imm:$src2), "adc $dst, $src2">; -def ADC32mi : Im32i32<"adc", 0x81, MRM2m >; // [mem32] += I32+Carry -def ADC32mi8 : Im32i8 <"adc", 0x83, MRM2m >; // [mem32] += I8+Carry +def ADC32rm : I<0x13, MRMSrcMem , (ops R32:$dst, R32:$src1, i32mem:$src2), "adc $dst, $src2">; +def ADC32ri : Ii32<0x81, MRM2r, (ops R32:$dst, R32:$src1, i32imm:$src2), "adc $dst, $src2">; +def ADC32ri8 : Ii8 <0x83, MRM2r, (ops R32:$dst, R32:$src1, i8imm:$src2), "adc $dst, $src2">; + +let isTwoAddress = 0 in { + def ADC32mr : I<0x11, MRMDestMem, (ops i32mem:$dst, i32imm:$src2), "adc $dst, $src2">; + def ADC32mi : Im32i32<"adc", 0x81, MRM2m >; // [mem32] += I32+Carry + def ADC32mi8 : Im32i8 <"adc", 0x83, MRM2m >; // [mem32] += I8+Carry +} def SUB8rr : I<0x28, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "sub $dst, $src2">; def SUB16rr : I<0x29, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "sub $dst, $src2">, OpSize; def SUB32rr : I<0x29, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "sub $dst, $src2">; -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] +let isTwoAddress = 0 in { + def SUB8mr : I<0x28, MRMDestMem, (ops i8mem :$dst, R8 :$src2), "sub $dst, $src2">; + def SUB16mr : I<0x29, MRMDestMem, (ops i16mem:$dst, R16:$src2), "sub $dst, $src2">, OpSize; + def SUB32mr : I<0x29, MRMDestMem, (ops i32mem:$dst, R32:$src2), "sub $dst, $src2">; +} +def SUB8rm : I<0x2A, MRMSrcMem, (ops R8 :$dst, R8 :$src1, i8mem :$src2), "sub $dst, $src2">; +def SUB16rm : I<0x2B, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), "sub $dst, $src2">, OpSize; +def SUB32rm : I<0x2B, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), "sub $dst, $src2">; def SUB8ri : Ii8 <0x80, MRM5r, (ops R8:$dst, R8:$src1, i8imm:$src2), "sub $dst, $src2">; @@ -688,32 +751,39 @@ "sub $dst, $src2">, OpSize; def SUB32ri : Ii32<0x81, MRM5r, (ops R32:$dst, R32:$src1, i32imm:$src2), "sub $dst, $src2">; -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 +let isTwoAddress = 0 in { + 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<0x83, MRM5r, (ops R16:$dst, R16:$src1, i8imm:$src2), "sub $dst, $src2">, OpSize; def SUB32ri8 : Ii8<0x83, MRM5r, (ops R32:$dst, R32:$src1, i8imm:$src2), "sub $dst, $src2">; -def SUB16mi8 : Im16i8<"sub", 0x83, MRM5m >, OpSize; // [mem16] -= I8 -def SUB32mi8 : Im32i8<"sub", 0x83, MRM5m >; // [mem32] -= I8 +let isTwoAddress = 0 in { + def SUB16mi8 : Im16i8<"sub", 0x83, MRM5m >, OpSize; // [mem16] -= I8 + def SUB32mi8 : Im32i8<"sub", 0x83, MRM5m >; // [mem32] -= I8 +} def SBB32rr : I<0x19, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "adc $dst, $src2">; -def SBB32mr : Im32<"sbb", 0x19, MRMDestMem>; // [mem32] -= R32+Carry -def SBB32rm : Im32<"sbb", 0x1B, MRMSrcMem >; // R32 -= [mem32]+Carry +let isTwoAddress = 0 in { + def SBB32mr : I<0x19, MRMDestMem, (ops i32mem:$dst, R32:$src2), "sbb $dst, $src2">; + def SBB32mi : Im32i32<"sbb", 0x81, MRM3m>; // [mem32] -= I32+Carry + def SBB32mi8 : Im32i8 <"sbb", 0x83, MRM3m>; // [mem32] -= I8+Carry +} +def SBB32rm : I<0x1B, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), + "sbb $dst, $src2">; def SBB32ri : Ii32<0x81, MRM3r, (ops R32:$dst, R32:$src1, i32imm:$src2), "sbb $dst, $src2">; def SBB32ri8 : Ii8<0x83, MRM3r, (ops R32:$dst, R32:$src1, i8imm:$src2), "sbb $dst, $src2">; -def SBB32mi : Im32i32<"sbb", 0x81, MRM3m>; // [mem32] -= I32+Carry -def SBB32mi8 : Im32i8 <"sbb", 0x83, MRM3m>; // [mem32] -= I8+Carry def IMUL16rr : I<0xAF, MRMSrcReg, (ops R16:$dst, R16:$src1, R16:$src2), "imul $dst, $src2">, TB, OpSize; def IMUL32rr : I<0xAF, MRMSrcReg, (ops R32:$dst, R32:$src1, R32:$src2), "imul $dst, $src2">, TB; -def IMUL16rm : Im16 <"imul", 0xAF, MRMSrcMem>, TB, OpSize; -def IMUL32rm : Im32 <"imul", 0xAF, MRMSrcMem>, TB ; +def IMUL16rm : I<0xAF, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), "imul $dst, $src2">, TB, OpSize; +def IMUL32rm : I<0xAF, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), "imul $dst, $src2">, TB ; } // end Two Address instructions @@ -739,12 +809,18 @@ "test $src1, $src2">, OpSize; def TEST32rr : I<0x85, MRMDestReg, (ops R32:$src1, R32:$src2), "test $src1, $src2">; -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 TEST8mr : I<0x84, MRMDestMem, (ops i8mem :$src1, R8 :$src2), + "test $src1, $src2">; +def TEST16mr : I<0x85, MRMDestMem, (ops i16mem:$src1, R16:$src2), + "test $src1, $src2">, OpSize; +def TEST32mr : I<0x85, MRMDestMem, (ops i32mem:$src1, R32:$src2), + "test $src1, $src2">; +def TEST8rm : I<0x84, MRMSrcMem, (ops R8 :$src1, i8mem :$src2), + "test $src1, $src2">; +def TEST16rm : I<0x85, MRMSrcMem, (ops R16:$src1, i16mem:$src2), + "test $src1, $src2">, OpSize; +def TEST32rm : I<0x85, MRMSrcMem, (ops R32:$src1, i32mem:$src2), + "test $src1, $src2">; def TEST8ri : Ii8 <0xF6, MRM0r, (ops R8:$dst, i8imm:$src), "test $dst, $src">; // flags = R8 & imm8 @@ -762,43 +838,43 @@ def SAHF : I<0x9E, RawFrm, (ops), "sahf">, Imp<[AH],[]>; // flags = AH def LAHF : I<0x9F, RawFrm, (ops), "lahf">, Imp<[],[AH]>; // AH = flags -def SETBr : I<0x92, MRM0r, (ops R8:$dst), "setb $dst">, TB; // R8 = < unsign -def SETBm : Im8<"setb" , 0x92, MRM0m>, TB; // [mem8] = < unsign -def SETAEr : I<0x93, MRM0r, (ops R8:$dst), "setae $dst">, TB; // R8 = >= unsign -def SETAEm : Im8<"setae", 0x93, MRM0m>, TB; // [mem8] = >= unsign -def SETEr : I<0x94, MRM0r, (ops R8:$dst), "sete $dst">, TB; // R8 = == -def SETEm : Im8<"sete" , 0x94, MRM0m>, TB; // [mem8] = == -def SETNEr : I<0x95, MRM0r, (ops R8:$dst), "setne $dst">, TB; // R8 = != -def SETNEm : Im8<"setne", 0x95, MRM0m>, TB; // [mem8] = != -def SETBEr : I<0x96, MRM0r, (ops R8:$dst), "setbe $dst">, TB; // R8 = <= unsign -def SETBEm : Im8<"setbe", 0x96, MRM0m>, TB; // [mem8] = <= unsign -def SETAr : I<0x97, MRM0r, (ops R8:$dst), "seta $dst">, TB; // R8 = > signed -def SETAm : Im8<"seta" , 0x97, MRM0m>, TB; // [mem8] = > signed -def SETSr : I<0x98, MRM0r, (ops R8:$dst), "sets $dst">, TB; // R8 = -def SETSm : Im8<"sets" , 0x98, MRM0m>, TB; // [mem8] = -def SETNSr : I<0x99, MRM0r, (ops R8:$dst), "setns $dst">, TB; // R8 = ! -def SETNSm : Im8<"setns", 0x99, MRM0m>, TB; // [mem8] = ! -def SETPr : I<0x9A, MRM0r, (ops R8:$dst), "setp $dst">, TB; // R8 = parity -def SETPm : Im8<"setp" , 0x9A, MRM0m>, TB; // [mem8] = parity -def SETLr : I<0x9C, MRM0r, (ops R8:$dst), "setl $dst">, TB; // R8 = < signed -def SETLm : Im8<"setl" , 0x9C, MRM0m>, TB; // [mem8] = < signed -def SETGEr : I<0x9D, MRM0r, (ops R8:$dst), "setge $dst">, TB; // R8 = >= signed -def SETGEm : Im8<"setge", 0x9D, MRM0m>, TB; // [mem8] = >= signed -def SETLEr : I<0x9E, MRM0r, (ops R8:$dst), "setle $dst">, TB; // R8 = <= signed -def SETLEm : Im8<"setle", 0x9E, MRM0m>, TB; // [mem8] = <= signed -def SETGr : I<0x9F, MRM0r, (ops R8:$dst), "setg $dst">, TB; // R8 = < signed -def SETGm : Im8<"setg" , 0x9F, MRM0m>, TB; // [mem8] = < signed +def SETBr : I<0x92, MRM0r, (ops R8 :$dst), "setb $dst">, TB; // R8 = < unsign +def SETBm : I<0x92, MRM0m, (ops i8mem:$dst), "setb $dst">, TB; // [mem8] = < unsign +def SETAEr : I<0x93, MRM0r, (ops R8 :$dst), "setae $dst">, TB; // R8 = >= unsign +def SETAEm : I<0x93, MRM0m, (ops i8mem:$dst), "setae $dst">, TB; // [mem8] = >= unsign +def SETEr : I<0x94, MRM0r, (ops R8 :$dst), "sete $dst">, TB; // R8 = == +def SETEm : I<0x94, MRM0m, (ops i8mem:$dst), "sete $dst">, TB; // [mem8] = == +def SETNEr : I<0x95, MRM0r, (ops R8 :$dst), "setne $dst">, TB; // R8 = != +def SETNEm : I<0x95, MRM0m, (ops i8mem:$dst), "setne $dst">, TB; // [mem8] = != +def SETBEr : I<0x96, MRM0r, (ops R8 :$dst), "setbe $dst">, TB; // R8 = <= unsign +def SETBEm : I<0x96, MRM0m, (ops i8mem:$dst), "setbe $dst">, TB; // [mem8] = <= unsign +def SETAr : I<0x97, MRM0r, (ops R8 :$dst), "seta $dst">, TB; // R8 = > signed +def SETAm : I<0x97, MRM0m, (ops i8mem:$dst), "seta $dst">, TB; // [mem8] = > signed +def SETSr : I<0x98, MRM0r, (ops R8 :$dst), "sets $dst">, TB; // R8 = +def SETSm : I<0x98, MRM0m, (ops i8mem:$dst), "sets $dst">, TB; // [mem8] = +def SETNSr : I<0x99, MRM0r, (ops R8 :$dst), "setns $dst">, TB; // R8 = ! +def SETNSm : I<0x99, MRM0m, (ops i8mem:$dst), "setns $dst">, TB; // [mem8] = ! +def SETPr : I<0x9A, MRM0r, (ops R8 :$dst), "setp $dst">, TB; // R8 = parity +def SETPm : I<0x9A, MRM0m, (ops i8mem:$dst), "setp $dst">, TB; // [mem8] = parity +def SETLr : I<0x9C, MRM0r, (ops R8 :$dst), "setl $dst">, TB; // R8 = < signed +def SETLm : I<0x9C, MRM0m, (ops i8mem:$dst), "setl $dst">, TB; // [mem8] = < signed +def SETGEr : I<0x9D, MRM0r, (ops R8 :$dst), "setge $dst">, TB; // R8 = >= signed +def SETGEm : I<0x9D, MRM0m, (ops i8mem:$dst), "setge $dst">, TB; // [mem8] = >= signed +def SETLEr : I<0x9E, MRM0r, (ops R8 :$dst), "setle $dst">, TB; // R8 = <= signed +def SETLEm : I<0x9E, MRM0m, (ops i8mem:$dst), "setle $dst">, TB; // [mem8] = <= signed +def SETGr : I<0x9F, MRM0r, (ops R8 :$dst), "setg $dst">, TB; // R8 = < signed +def SETGm : I<0x9F, MRM0m, (ops i8mem:$dst), "setg $dst">, TB; // [mem8] = < signed // Integer comparisons def CMP8rr : I<0x38, MRMDestReg, (ops R8 :$src1, R8 :$src2), "cmp $src1, $src2">; def CMP16rr : I<0x39, MRMDestReg, (ops R16:$src1, R16:$src2), "cmp $src1, $src2">, OpSize; def CMP32rr : I<0x39, MRMDestReg, (ops R32:$src1, R32:$src2), "cmp $src1, $src2">; -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 CMP8mr : I<0x38, MRMDestMem, (ops i8mem :$src1, R8 :$src2), "cmp $src1, $src2">; +def CMP16mr : I<0x39, MRMDestMem, (ops i16mem:$src1, R16:$src2), "cmp $src1, $src2">, OpSize; +def CMP32mr : I<0x39, MRMDestMem, (ops i32mem:$src1, R32:$src2), "cmp $src1, $src2">; +def CMP8rm : I<0x3A, MRMSrcMem , (ops R8 :$src1, i8mem :$src2), "cmp $src1, $src2">; +def CMP16rm : I<0x3B, MRMSrcMem , (ops R16:$src1, i16mem:$src2), "cmp $src1, $src2">, OpSize; +def CMP32rm : I<0x3B, MRMSrcMem , (ops R32:$src1, i32mem:$src2), "cmp $src1, $src2">; def CMP8ri : Ii8 <0x80, MRM7r, (ops R16:$dst, i8imm:$src), "cmp $dst, $src">; def CMP16ri : Ii16 <0x81, MRM7r, (ops R16:$dst, i16imm:$src), "cmp $dst, $src">, OpSize; def CMP32ri : Ii32 <0x81, MRM7r, (ops R32:$dst, i32imm:$src), "cmp $dst, $src">; @@ -810,16 +886,16 @@ def MOVSX16rr8 : I<0xBE, MRMSrcReg, (ops R16:$dst, R8 :$src), "movsx $dst, $src">, TB, OpSize; def MOVSX32rr8 : I<0xBE, MRMSrcReg, (ops R32:$dst, R8 :$src), "movsx $dst, $src">, TB; def MOVSX32rr16: I<0xBF, MRMSrcReg, (ops R32:$dst, R16:$src), "movsx $dst, $src">, TB; -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 MOVSX16rm8 : I<0xBE, MRMSrcMem, (ops R16:$dst, i8mem :$src), "movsx $dst, $src">, TB, OpSize; +def MOVSX32rm8 : I<0xBE, MRMSrcMem, (ops R32:$dst, i8mem :$src), "movsx $dst, $src">, TB; +def MOVSX32rm16: I<0xBF, MRMSrcMem, (ops R32:$dst, i16mem:$src), "movsx $dst, $src">, TB; def MOVZX16rr8 : I<0xB6, MRMSrcReg, (ops R16:$dst, R8 :$src), "movzx $dst, $src">, TB, OpSize; def MOVZX32rr8 : I<0xB6, MRMSrcReg, (ops R32:$dst, R8 :$src), "movzx $dst, $src">, TB; def MOVZX32rr16: I<0xB7, MRMSrcReg, (ops R32:$dst, R16:$src), "movzx $dst, $src">, TB; -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]) +def MOVZX16rm8 : I<0xB6, MRMSrcMem, (ops R16:$dst, i8mem :$src), "movzx $dst, $src">, TB, OpSize; +def MOVZX32rm8 : I<0xB6, MRMSrcMem, (ops R32:$dst, i8mem :$src), "movzx $dst, $src">, TB; +def MOVZX32rm16: I<0xB7, MRMSrcMem, (ops R32:$dst, i16mem:$src), "movzx $dst, $src">, TB; //===----------------------------------------------------------------------===// @@ -1004,5 +1080,5 @@ // Floating point flag ops def FNSTSW8r : I<0xE0, RawFrm, (ops), "fnstsw">, 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] +def FNSTCW16m : I<0xD9, MRM7m, (ops i16mem:$dst), "fnstcw $dst">; // [mem16] = X87 control world +def FLDCW16m : I<0xD9, MRM5m, (ops i16mem:$dst), "fldcw $dst">; // X87 control world = [mem16] From lattner at cs.uiuc.edu Wed Aug 11 00:07:37 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 00:07:37 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200408110507.AAA20446@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.95 -> 1.96 --- Log message: X86 instructions that read-modify-write memory are not LLVM two-address instructions. --- Diffs of the changes: (+60 -78) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.95 llvm/lib/Target/X86/X86InstrInfo.td:1.96 --- llvm/lib/Target/X86/X86InstrInfo.td:1.95 Tue Aug 10 23:31:00 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Wed Aug 11 00:07:25 2004 @@ -513,12 +513,6 @@ def AND16rr : I<0x21, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "and $dst, $src2">, OpSize; def AND32rr : I<0x21, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "and $dst, $src2">; -let isTwoAddress = 0 in { - def AND8mr : I<0x20, MRMDestMem, (ops i8mem :$dst, R8 :$src), "and $dst, $src">; - def AND16mr : I<0x21, MRMDestMem, (ops i16mem:$dst, R16:$src), "and $dst, $src">, OpSize; - def AND32mr : I<0x21, MRMDestMem, (ops i32mem:$dst, R32:$src), "and $dst, $src">; -} - def AND8rm : I<0x22, MRMSrcMem , (ops R8 :$dst, R8 :$src1, i8mem :$src2), "and $dst, $src2">; def AND16rm : I<0x23, MRMSrcMem , (ops R16:$dst, R16:$src1, i16mem:$src2), "and $dst, $src2">, OpSize; def AND32rm : I<0x23, MRMSrcMem , (ops R32:$dst, R32:$src1, i32mem:$src2), "and $dst, $src2">; @@ -529,16 +523,22 @@ "and $dst, $src2">, OpSize; def AND32ri : Ii32<0x81, MRM4r, (ops R32:$dst, R32:$src1, i32imm:$src2), "and $dst, $src2">; -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<0x83, MRM4r, (ops R16:$dst, R16:$src1, i8imm:$src2), "and $dst, $src2" >, OpSize; def AND32ri8 : Ii8<0x83, MRM4r, (ops R32:$dst, R32:$src1, i8imm:$src2), "and $dst, $src2">; -def AND16mi8 : Im16i8<"and", 0x83, MRM4m >, OpSize; // [mem16] &= imm8 -def AND32mi8 : Im32i8<"and", 0x83, MRM4m >; // [mem32] &= imm8 + +let isTwoAddress = 0 in { + def AND8mr : I<0x20, MRMDestMem, (ops i8mem :$dst, R8 :$src), "and $dst, $src">; + def AND16mr : I<0x21, MRMDestMem, (ops i16mem:$dst, R16:$src), "and $dst, $src">, OpSize; + def AND32mr : I<0x21, MRMDestMem, (ops i32mem:$dst, R32:$src), "and $dst, $src">; + 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 AND16mi8 : Im16i8<"and", 0x83, MRM4m >, OpSize; // [mem16] &= imm8 + def AND32mi8 : Im32i8<"and", 0x83, MRM4m >; // [mem32] &= imm8 +} + def OR8rr : I<0x08, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), @@ -547,14 +547,6 @@ "or $dst, $src2">, OpSize; def OR32rr : I<0x09, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "or $dst, $src2">; -let isTwoAddress = 0 in { - def OR8mr : I<0x08, MRMDestMem, (ops i8mem:$dst, R8:$src), - "or $dst, $src">; - def OR16mr : I<0x09, MRMDestMem, (ops i16mem:$dst, R16:$src), - "or $dst, $src">, OpSize; - def OR32mr : I<0x09, MRMDestMem, (ops i32mem:$dst, R32:$src), - "or $dst, $src">; -} def OR8rm : I<0x0A, MRMSrcMem , (ops R8 :$dst, R8 :$src1, i8mem :$src2), "or $dst, $src2">; def OR16rm : I<0x0B, MRMSrcMem , (ops R16:$dst, R16:$src1, i16mem:$src2), @@ -568,17 +560,21 @@ "or $dst, $src2">, OpSize; def OR32ri : Ii32<0x81, MRM1r, (ops R32:$dst, R32:$src1, i32imm:$src2), "or $dst, $src2">; -let isTwoAddress = 0 in { - 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<0x83, MRM1r, (ops R8 :$dst, R8 :$src1, i8imm:$src2), "or $dst, $src2">, OpSize; def OR32ri8 : Ii8<0x83, MRM1r, (ops R32:$dst, R32:$src1, i8imm:$src2), "or $dst, $src2">; let isTwoAddress = 0 in { + def OR8mr : I<0x08, MRMDestMem, (ops i8mem:$dst, R8:$src), + "or $dst, $src">; + def OR16mr : I<0x09, MRMDestMem, (ops i16mem:$dst, R16:$src), + "or $dst, $src">, OpSize; + def OR32mr : I<0x09, MRMDestMem, (ops i32mem:$dst, R32:$src), + "or $dst, $src">; + 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 OR16mi8 : Im16i8<"or" , 0x83, MRM1m>, OpSize; // [mem16] |= imm8 def OR32mi8 : Im32i8<"or" , 0x83, MRM1m>; // [mem32] |= imm8 } @@ -587,11 +583,6 @@ def XOR8rr : I<0x30, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "xor $dst, $src2">; def XOR16rr : I<0x31, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "xor $dst, $src2">, OpSize; def XOR32rr : I<0x31, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "xor $dst, $src2">; -let isTwoAddress = 0 in { - def XOR8mr : I<0x30, MRMDestMem, (ops i8mem :$dst, R8 :$src), "xor $dst, $src">; - def XOR16mr: I<0x31, MRMDestMem, (ops i16mem:$dst, R16:$src), "xor $dst, $src">, OpSize; - def XOR32mr: I<0x31, MRMDestMem, (ops i32mem:$dst, R32:$src), "xor $dst, $src">; -} def XOR8rm : I<0x32, MRMSrcMem , (ops R8 :$dst, R8:$src1, i8mem :$src2), "xor $dst, $src2">; def XOR16rm : I<0x33, MRMSrcMem , (ops R16:$dst, R8:$src1, i16mem:$src2), "xor $dst, $src2">, OpSize; def XOR32rm : I<0x33, MRMSrcMem , (ops R32:$dst, R8:$src1, i32mem:$src2), "xor $dst, $src2">; @@ -599,16 +590,17 @@ def XOR8ri : Ii8 <0x80, MRM6r, (ops R8:$dst, R8:$src1, i8imm:$src2), "xor $dst, $src2">; def XOR16ri : Ii16 <0x81, MRM6r, (ops R16:$dst, R16:$src1, i16imm:$src2), "xor $dst, $src2">, OpSize; def XOR32ri : Ii32 <0x81, MRM6r, (ops R32:$dst, R32:$src1, i32imm:$src2), "xor $dst, $src2">; -let isTwoAddress = 0 in { - 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<0x83, MRM6r, (ops R16:$dst, R16:$src1, i8imm:$src2), "xor $dst, $src2">, OpSize; def XOR32ri8 : Ii8<0x83, MRM6r, (ops R32:$dst, R32:$src1, i8imm:$src2), "xor $dst, $src2">; let isTwoAddress = 0 in { + def XOR8mr : I<0x30, MRMDestMem, (ops i8mem :$dst, R8 :$src), "xor $dst, $src">; + def XOR16mr: I<0x31, MRMDestMem, (ops i16mem:$dst, R16:$src), "xor $dst, $src">, OpSize; + def XOR32mr: I<0x31, MRMDestMem, (ops i32mem:$dst, R32:$src), "xor $dst, $src">; + 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 XOR16mi8 : Im16i8<"xor", 0x83, MRM6m >, OpSize; // [mem16] ^= imm8 def XOR32mi8 : Im32i8<"xor", 0x83, MRM6m >; // [mem32] ^= imm8 } @@ -618,35 +610,34 @@ def SHL8rCL : I<0xD2, MRM4r, (ops R8 :$dst, R8 :$src), "shl $dst, %CL">, Imp<[CL],[]>; def SHL16rCL : I<0xD3, MRM4r, (ops R16:$dst, R16:$src), "shl $dst, %CL">, Imp<[CL],[]>, OpSize; def SHL32rCL : I<0xD3, MRM4r, (ops R32:$dst, R32:$src), "shl $dst, %CL">, Imp<[CL],[]>; -let isTwoAddress = 0 in { - def SHL8mCL : I<0xD2, MRM4m, (ops i8mem :$dst), "shl $dst, %CL">, Imp<[CL],[]>; - def SHL16mCL : I<0xD3, MRM4m, (ops i16mem:$dst), "shl $dst, %CL">, Imp<[CL],[]>, OpSize; - def SHL32mCL : I<0xD3, MRM4m, (ops i32mem:$dst), "shl $dst, %CL">, Imp<[CL],[]>; -} - def SHL8ri : Ii8<0xC0, MRM4r, (ops R8 :$dst, R8 :$src1, i8imm:$src2), "shl $dst, $src2">; def SHL16ri : Ii8<0xC1, MRM4r, (ops R16:$dst, R16:$src1, i8imm:$src2), "shl $dst, $src2">, OpSize; def SHL32ri : Ii8<0xC1, MRM4r, (ops R32:$dst, R32:$src1, i8imm:$src2), "shl $dst, $src2">; -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 + +let isTwoAddress = 0 in { + def SHL8mCL : I<0xD2, MRM4m, (ops i8mem :$dst), "shl $dst, %CL">, Imp<[CL],[]>; + def SHL16mCL : I<0xD3, MRM4m, (ops i16mem:$dst), "shl $dst, %CL">, Imp<[CL],[]>, OpSize; + def SHL32mCL : I<0xD3, MRM4m, (ops i32mem:$dst), "shl $dst, %CL">, Imp<[CL],[]>; + 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<0xD2, MRM5r, (ops R8 :$dst, R8 :$src), "shr $dst, %CL">, Imp<[CL],[]>; def SHR16rCL : I<0xD3, MRM5r, (ops R16:$dst, R16:$src), "shr $dst, %CL">, Imp<[CL],[]>, OpSize; def SHR32rCL : I<0xD3, MRM5r, (ops R32:$dst, R32:$src), "shr $dst, %CL">, Imp<[CL],[]>; -let isTwoAddress = 0 in { - def SHR8mCL : I<0xD2, MRM5m, (ops i8mem :$dst), "shr $dst, %CL">, Imp<[CL],[]>; - def SHR16mCL : I<0xD3, MRM5m, (ops i16mem:$dst), "shr $dst, %CL">, Imp<[CL],[]>, OpSize; - def SHR32mCL : I<0xD3, MRM5m, (ops i32mem:$dst), "shr $dst, %CL">, Imp<[CL],[]>; -} def SHR8ri : Ii8 <0xC0, MRM5r, (ops R8:$dst, R8:$src1, i8imm:$src2), "shr $dst, $src2">; def SHR16ri : Ii8 <0xC1, MRM5r, (ops R16:$dst, R16:$src1, i8imm:$src2), "shr $dst, $src2">, OpSize; def SHR32ri : Ii8 <0xC1, MRM5r, (ops R32:$dst, R32:$src1, i8imm:$src2), "shr $dst, $src2">; + let isTwoAddress = 0 in { + def SHR8mCL : I<0xD2, MRM5m, (ops i8mem :$dst), "shr $dst, %CL">, Imp<[CL],[]>; + def SHR16mCL : I<0xD3, MRM5m, (ops i16mem:$dst), "shr $dst, %CL">, Imp<[CL],[]>, OpSize; + def SHR32mCL : I<0xD3, MRM5m, (ops i32mem:$dst), "shr $dst, %CL">, Imp<[CL],[]>; def SHR8mi : Ii8 <0xC0, MRM5m, (ops i8mem :$dst, i8imm:$src), "shr $dst, $src">; def SHR16mi : Ii8<0xC1, MRM5m, (ops i16mem:$dst, i8imm:$src), "shr $dst, $src">, OpSize; def SHR32mi : Ii8<0xC1, MRM5m, (ops i32mem:$dst, i8imm:$src), "shr $dst, $src">; @@ -655,11 +646,6 @@ def SAR8rCL : I<0xD2, MRM7r, (ops R8 :$dst, R8 :$src), "sar $dst, %CL">, Imp<[CL],[]>; def SAR16rCL : I<0xD3, MRM7r, (ops R16:$dst, R16:$src), "sar $dst, %CL">, Imp<[CL],[]>, OpSize; def SAR32rCL : I<0xD3, MRM7r, (ops R32:$dst, R32:$src), "sar $dst, %CL">, Imp<[CL],[]>; -let isTwoAddress = 0 in { - def SAR8mCL : I<0xD2, MRM7m, (ops i8mem :$dst), "sar $dst, %CL">, Imp<[CL],[]>; - def SAR16mCL : I<0xD3, MRM7m, (ops i16mem:$dst), "sar $dst, %CL">, Imp<[CL],[]>, OpSize; - def SAR32mCL : I<0xD3, MRM7m, (ops i32mem:$dst), "sar $dst, %CL">, Imp<[CL],[]>; -} def SAR8ri : Ii8<0xC0, MRM7r, (ops R8 :$dst, R8 :$src1, i8imm:$src2), "sar $dst, $src2">; @@ -667,9 +653,14 @@ "sar $dst, $src2">, OpSize; def SAR32ri : Ii8<0xC1, MRM7r, (ops R32:$dst, R32:$src1, i8imm:$src2), "sar $dst, $src2">; -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 +let isTwoAddress = 0 in { + def SAR8mCL : I<0xD2, MRM7m, (ops i8mem :$dst), "sar $dst, %CL">, Imp<[CL],[]>; + def SAR16mCL : I<0xD3, MRM7m, (ops i16mem:$dst), "sar $dst, %CL">, Imp<[CL],[]>, OpSize; + def SAR32mCL : I<0xD3, MRM7m, (ops i32mem:$dst), "sar $dst, %CL">, Imp<[CL],[]>; + 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<0xA5, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "shld $dst, $src2, %CL">, Imp<[CL],[]>, TB; @@ -696,11 +687,6 @@ def ADD8rr : I<0x00, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "add $dst, $src2">; def ADD16rr : I<0x01, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "add $dst, $src2">, OpSize; def ADD32rr : I<0x01, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "add $dst, $src2">; -let isTwoAddress = 0 in { - def ADD8mr : I<0x00, MRMDestMem, (ops i8mem :$dst, R8 :$src2), "add $dst, $src2">; - def ADD16mr : I<0x01, MRMDestMem, (ops i16mem:$dst, R16:$src2), "add $dst, $src2">, OpSize; - def ADD32mr : I<0x01, MRMDestMem, (ops i32mem:$dst, R32:$src2), "add $dst, $src2">; -} def ADD8rm : I<0x02, MRMSrcMem, (ops R8 :$dst, R8 :$src1, i8mem :$src2), "add $dst, $src2">; def ADD16rm : I<0x03, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), "add $dst, $src2">, OpSize; def ADD32rm : I<0x03, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), "add $dst, $src2">; @@ -708,16 +694,17 @@ def ADD8ri : Ii8 <0x80, MRM0r, (ops R8:$dst, R8:$src1, i8imm:$src2), "add $dst, $src2">; def ADD16ri : Ii16 <0x81, MRM0r, (ops R16:$dst, R16:$src1, i16imm:$src2), "add $dst, $src2">, OpSize; def ADD32ri : Ii32 <0x81, MRM0r, (ops R32:$dst, R32:$src1, i32imm:$src2), "add $dst, $src2">; -let isTwoAddress = 0 in { - 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 <0x83, MRM0r, (ops R16:$dst, R16:$src1, i8imm:$src2), "add $dst, $src2">, OpSize; def ADD32ri8 : Ii8 <0x83, MRM0r, (ops R32:$dst, R32:$src1, i8imm:$src2), "add $dst, $src2">; let isTwoAddress = 0 in { + def ADD8mr : I<0x00, MRMDestMem, (ops i8mem :$dst, R8 :$src2), "add $dst, $src2">; + def ADD16mr : I<0x01, MRMDestMem, (ops i16mem:$dst, R16:$src2), "add $dst, $src2">, OpSize; + def ADD32mr : I<0x01, MRMDestMem, (ops i32mem:$dst, R32:$src2), "add $dst, $src2">; + 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 ADD16mi8 : Im16i8<"add", 0x83, MRM0m >, OpSize; // [mem16] += I8 def ADD32mi8 : Im32i8<"add", 0x83, MRM0m >; // [mem32] += I8 } @@ -736,11 +723,6 @@ def SUB8rr : I<0x28, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "sub $dst, $src2">; def SUB16rr : I<0x29, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), "sub $dst, $src2">, OpSize; def SUB32rr : I<0x29, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "sub $dst, $src2">; -let isTwoAddress = 0 in { - def SUB8mr : I<0x28, MRMDestMem, (ops i8mem :$dst, R8 :$src2), "sub $dst, $src2">; - def SUB16mr : I<0x29, MRMDestMem, (ops i16mem:$dst, R16:$src2), "sub $dst, $src2">, OpSize; - def SUB32mr : I<0x29, MRMDestMem, (ops i32mem:$dst, R32:$src2), "sub $dst, $src2">; -} def SUB8rm : I<0x2A, MRMSrcMem, (ops R8 :$dst, R8 :$src1, i8mem :$src2), "sub $dst, $src2">; def SUB16rm : I<0x2B, MRMSrcMem, (ops R16:$dst, R16:$src1, i16mem:$src2), "sub $dst, $src2">, OpSize; def SUB32rm : I<0x2B, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), "sub $dst, $src2">; @@ -751,17 +733,17 @@ "sub $dst, $src2">, OpSize; def SUB32ri : Ii32<0x81, MRM5r, (ops R32:$dst, R32:$src1, i32imm:$src2), "sub $dst, $src2">; -let isTwoAddress = 0 in { - 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<0x83, MRM5r, (ops R16:$dst, R16:$src1, i8imm:$src2), "sub $dst, $src2">, OpSize; def SUB32ri8 : Ii8<0x83, MRM5r, (ops R32:$dst, R32:$src1, i8imm:$src2), "sub $dst, $src2">; let isTwoAddress = 0 in { + def SUB8mr : I<0x28, MRMDestMem, (ops i8mem :$dst, R8 :$src2), "sub $dst, $src2">; + def SUB16mr : I<0x29, MRMDestMem, (ops i16mem:$dst, R16:$src2), "sub $dst, $src2">, OpSize; + def SUB32mr : I<0x29, MRMDestMem, (ops i32mem:$dst, R32:$src2), "sub $dst, $src2">; + 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 SUB16mi8 : Im16i8<"sub", 0x83, MRM5m >, OpSize; // [mem16] -= I8 def SUB32mi8 : Im32i8<"sub", 0x83, MRM5m >; // [mem32] -= I8 } From lattner at cs.uiuc.edu Wed Aug 11 00:31:19 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 00:31:19 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200408110531.AAA25405@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.96 -> 1.97 --- Log message: Nuke the Im*i* patterns, by asmprintergenifying all users. --- Diffs of the changes: (+73 -70) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.96 llvm/lib/Target/X86/X86InstrInfo.td:1.97 --- llvm/lib/Target/X86/X86InstrInfo.td:1.96 Wed Aug 11 00:07:25 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Wed Aug 11 00:31:07 2004 @@ -67,12 +67,10 @@ bits<3> Value = val; } def NoMem : MemType<0>; -def Mem8 : MemType<1>; def Mem16 : MemType<2>; def Mem32 : MemType<3>; def Mem64 : MemType<4>; def Mem80 : MemType<5>; -def Mem128 : MemType<6>; // FPFormat - This specifies what form this FP instruction has. This is used by // the Floating-Point stackifier pass. @@ -151,13 +149,6 @@ class Ii16 o, Format f, dag ops, string asm> : Ii, II; class Ii32 o, Format f, dag ops, string asm> : Ii, 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; - //===----------------------------------------------------------------------===// // Instruction list... // @@ -532,15 +523,14 @@ def AND8mr : I<0x20, MRMDestMem, (ops i8mem :$dst, R8 :$src), "and $dst, $src">; def AND16mr : I<0x21, MRMDestMem, (ops i16mem:$dst, R16:$src), "and $dst, $src">, OpSize; def AND32mr : I<0x21, MRMDestMem, (ops i32mem:$dst, R32:$src), "and $dst, $src">; - 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 AND16mi8 : Im16i8<"and", 0x83, MRM4m >, OpSize; // [mem16] &= imm8 - def AND32mi8 : Im32i8<"and", 0x83, MRM4m >; // [mem32] &= imm8 + def AND8mi : Ii8 <0x80, MRM4m, (ops i8mem :$dst, i8imm :$src), "and $dst, $src">; + def AND16mi : Ii16<0x81, MRM4m, (ops i16mem:$dst, i16imm:$src), "and $dst, $src">, OpSize; + def AND32mi : Ii32<0x81, MRM4m, (ops i32mem:$dst, i32imm:$src), "and $dst, $src">; + def AND16mi8 : Ii8 <0x83, MRM4m, (ops i16mem:$dst, i8imm :$src), "and $dst, $src">, OpSize; + def AND32mi8 : Ii8 <0x83, MRM4m, (ops i32mem:$dst, i8imm :$src), "and $dst, $src">; } - def OR8rr : I<0x08, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "or $dst, $src2">; def OR16rr : I<0x09, MRMDestReg, (ops R16:$dst, R16:$src1, R16:$src2), @@ -572,11 +562,16 @@ "or $dst, $src">, OpSize; def OR32mr : I<0x09, MRMDestMem, (ops i32mem:$dst, R32:$src), "or $dst, $src">; - 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 OR16mi8 : Im16i8<"or" , 0x83, MRM1m>, OpSize; // [mem16] |= imm8 - def OR32mi8 : Im32i8<"or" , 0x83, MRM1m>; // [mem32] |= imm8 + def OR8mi : Ii8<0x80, MRM1m, (ops i8mem :$dst, i8imm:$src), + "or $dst, $src">; + def OR16mi : Ii16<0x81, MRM1m, (ops i16mem:$dst, i16imm:$src), + "or $dst, $src">, OpSize; + def OR32mi : Ii32<0x81, MRM1m, (ops i32mem:$dst, i32imm:$src), + "or $dst, $src">; + def OR16mi8 : Ii8<0x83, MRM1m, (ops i16mem:$dst, i8imm:$src), + "or $dst, $src">, OpSize; + def OR32mi8 : Ii8<0x83, MRM1m, (ops i32mem:$dst, i8imm:$src), + "or $dst, $src">; } @@ -595,14 +590,14 @@ def XOR32ri8 : Ii8<0x83, MRM6r, (ops R32:$dst, R32:$src1, i8imm:$src2), "xor $dst, $src2">; let isTwoAddress = 0 in { - def XOR8mr : I<0x30, MRMDestMem, (ops i8mem :$dst, R8 :$src), "xor $dst, $src">; - def XOR16mr: I<0x31, MRMDestMem, (ops i16mem:$dst, R16:$src), "xor $dst, $src">, OpSize; - def XOR32mr: I<0x31, MRMDestMem, (ops i32mem:$dst, R32:$src), "xor $dst, $src">; - 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 XOR16mi8 : Im16i8<"xor", 0x83, MRM6m >, OpSize; // [mem16] ^= imm8 - def XOR32mi8 : Im32i8<"xor", 0x83, MRM6m >; // [mem32] ^= imm8 + def XOR8mr : I<0x30, MRMDestMem, (ops i8mem :$dst, R8 :$src), "xor $dst, $src">; + def XOR16mr : I<0x31, MRMDestMem, (ops i16mem:$dst, R16:$src), "xor $dst, $src">, OpSize; + def XOR32mr : I<0x31, MRMDestMem, (ops i32mem:$dst, R32:$src), "xor $dst, $src">; + def XOR8mi : Ii8 <0x80, MRM6m, (ops i8mem :$dst, i8imm :$src), "xor $dst, $src">; + def XOR16mi : Ii16<0x81, MRM6m, (ops i16mem:$dst, i16imm:$src), "xor $dst, $src">, OpSize; + def XOR32mi : Ii32<0x81, MRM6m, (ops i32mem:$dst, i32imm:$src), "xor $dst, $src">; + def XOR16mi8 : Ii8 <0x83, MRM6m, (ops i16mem:$dst, i8imm :$src), "xor $dst, $src">, OpSize; + def XOR32mi8 : Ii8 <0x83, MRM6m, (ops i32mem:$dst, i8imm :$src), "xor $dst, $src">; } // Shift instructions @@ -621,9 +616,9 @@ def SHL8mCL : I<0xD2, MRM4m, (ops i8mem :$dst), "shl $dst, %CL">, Imp<[CL],[]>; def SHL16mCL : I<0xD3, MRM4m, (ops i16mem:$dst), "shl $dst, %CL">, Imp<[CL],[]>, OpSize; def SHL32mCL : I<0xD3, MRM4m, (ops i32mem:$dst), "shl $dst, %CL">, Imp<[CL],[]>; - 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 SHL8mi : Ii8<0xC0, MRM4m, (ops i8mem :$dst, i8imm:$src), "shl $dst, $src">; + def SHL16mi : Ii8<0xC1, MRM4m, (ops i16mem:$dst, i8imm:$src), "shl $dst, $src">, OpSize; + def SHL32mi : Ii8<0xC1, MRM4m, (ops i32mem:$dst, i8imm:$src), "shl $dst, $src">; } def SHR8rCL : I<0xD2, MRM5r, (ops R8 :$dst, R8 :$src), "shr $dst, %CL">, Imp<[CL],[]>; @@ -638,7 +633,7 @@ def SHR8mCL : I<0xD2, MRM5m, (ops i8mem :$dst), "shr $dst, %CL">, Imp<[CL],[]>; def SHR16mCL : I<0xD3, MRM5m, (ops i16mem:$dst), "shr $dst, %CL">, Imp<[CL],[]>, OpSize; def SHR32mCL : I<0xD3, MRM5m, (ops i32mem:$dst), "shr $dst, %CL">, Imp<[CL],[]>; - def SHR8mi : Ii8 <0xC0, MRM5m, (ops i8mem :$dst, i8imm:$src), "shr $dst, $src">; + def SHR8mi : Ii8<0xC0, MRM5m, (ops i8mem :$dst, i8imm:$src), "shr $dst, $src">; def SHR16mi : Ii8<0xC1, MRM5m, (ops i16mem:$dst, i8imm:$src), "shr $dst, $src">, OpSize; def SHR32mi : Ii8<0xC1, MRM5m, (ops i32mem:$dst, i8imm:$src), "shr $dst, $src">; } @@ -657,9 +652,9 @@ def SAR8mCL : I<0xD2, MRM7m, (ops i8mem :$dst), "sar $dst, %CL">, Imp<[CL],[]>; def SAR16mCL : I<0xD3, MRM7m, (ops i16mem:$dst), "sar $dst, %CL">, Imp<[CL],[]>, OpSize; def SAR32mCL : I<0xD3, MRM7m, (ops i32mem:$dst), "sar $dst, %CL">, Imp<[CL],[]>; - 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 SAR8mi : Ii8<0xC0, MRM7m, (ops i8mem :$dst, i8imm:$src), "sar $dst, $src">; + def SAR16mi : Ii8<0xC1, MRM7m, (ops i16mem:$dst, i8imm:$src), "sar $dst, $src">, OpSize; + def SAR32mi : Ii8<0xC1, MRM7m, (ops i32mem:$dst, i8imm:$src), "sar $dst, $src">; } def SHLD32rrCL : I<0xA5, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), @@ -702,11 +697,11 @@ def ADD8mr : I<0x00, MRMDestMem, (ops i8mem :$dst, R8 :$src2), "add $dst, $src2">; def ADD16mr : I<0x01, MRMDestMem, (ops i16mem:$dst, R16:$src2), "add $dst, $src2">, OpSize; def ADD32mr : I<0x01, MRMDestMem, (ops i32mem:$dst, R32:$src2), "add $dst, $src2">; - 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 ADD16mi8 : Im16i8<"add", 0x83, MRM0m >, OpSize; // [mem16] += I8 - def ADD32mi8 : Im32i8<"add", 0x83, MRM0m >; // [mem32] += I8 + def ADD8mi : Ii8 <0x80, MRM0m, (ops i8mem :$dst, i8imm :$src2), "add $dst, $src2">; + def ADD16mi : Ii16<0x81, MRM0m, (ops i16mem:$dst, i16imm:$src2), "add $dst, $src2">, OpSize; + def ADD32mi : Ii32<0x81, MRM0m, (ops i32mem:$dst, i32imm:$src2), "add $dst, $src2">; + def ADD16mi8 : Ii8 <0x83, MRM0m, (ops i16mem:$dst, i8imm :$src2), "add $dst, $src2">, OpSize; + def ADD32mi8 : Ii8 <0x83, MRM0m, (ops i32mem:$dst, i8imm :$src2), "add $dst, $src2">; } def ADC32rr : I<0x11, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "adc $dst, $src2">; @@ -715,9 +710,9 @@ def ADC32ri8 : Ii8 <0x83, MRM2r, (ops R32:$dst, R32:$src1, i8imm:$src2), "adc $dst, $src2">; let isTwoAddress = 0 in { - def ADC32mr : I<0x11, MRMDestMem, (ops i32mem:$dst, i32imm:$src2), "adc $dst, $src2">; - def ADC32mi : Im32i32<"adc", 0x81, MRM2m >; // [mem32] += I32+Carry - def ADC32mi8 : Im32i8 <"adc", 0x83, MRM2m >; // [mem32] += I8+Carry + def ADC32mr : I<0x11, MRMDestMem, (ops i32mem:$dst, R32:$src2), "adc $dst, $src2">; + def ADC32mi : Ii32<0x81, MRM2m, (ops i32mem:$dst, i32imm:$src2), "adc $dst, $src2">; + def ADC32mi8 : Ii8 <0x83, MRM2m, (ops i32mem:$dst, i8imm :$src2), "adc $dst, $src2">; } def SUB8rr : I<0x28, MRMDestReg, (ops R8 :$dst, R8 :$src1, R8 :$src2), "sub $dst, $src2">; @@ -741,19 +736,19 @@ def SUB8mr : I<0x28, MRMDestMem, (ops i8mem :$dst, R8 :$src2), "sub $dst, $src2">; def SUB16mr : I<0x29, MRMDestMem, (ops i16mem:$dst, R16:$src2), "sub $dst, $src2">, OpSize; def SUB32mr : I<0x29, MRMDestMem, (ops i32mem:$dst, R32:$src2), "sub $dst, $src2">; - 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 SUB16mi8 : Im16i8<"sub", 0x83, MRM5m >, OpSize; // [mem16] -= I8 - def SUB32mi8 : Im32i8<"sub", 0x83, MRM5m >; // [mem32] -= I8 + def SUB8mi : Ii8 <0x80, MRM5m, (ops i8mem :$dst, i8imm:$src2), "sub $dst, $src2">; + def SUB16mi : Ii16<0x81, MRM5m, (ops i16mem:$dst, i16imm:$src2), "sub $dst, $src2">, OpSize; + def SUB32mi : Ii32<0x81, MRM5m, (ops i32mem:$dst, i32imm:$src2), "sub $dst, $src2">; + def SUB16mi8 : Ii8 <0x83, MRM5m, (ops i16mem:$dst, i8imm :$src2), "sub $dst, $src2">, OpSize; + def SUB32mi8 : Ii8 <0x83, MRM5m, (ops i32mem:$dst, i8imm :$src2), "sub $dst, $src2">; } def SBB32rr : I<0x19, MRMDestReg, (ops R32:$dst, R32:$src1, R32:$src2), "adc $dst, $src2">; let isTwoAddress = 0 in { def SBB32mr : I<0x19, MRMDestMem, (ops i32mem:$dst, R32:$src2), "sbb $dst, $src2">; - def SBB32mi : Im32i32<"sbb", 0x81, MRM3m>; // [mem32] -= I32+Carry - def SBB32mi8 : Im32i8 <"sbb", 0x83, MRM3m>; // [mem32] -= I8+Carry + def SBB32mi : Ii32<0x81, MRM3m, (ops i32mem:$dst, i32imm:$src2), "sbb $dst, $src2">; + def SBB32mi8 : Ii8 <0x83, MRM3m, (ops i32mem:$dst, i8imm :$src2), "sbb $dst, $src2">; } def SBB32rm : I<0x1B, MRMSrcMem, (ops R32:$dst, R32:$src1, i32mem:$src2), "sbb $dst, $src2">; @@ -769,7 +764,7 @@ } // end Two Address instructions -// These are suprisingly enough not two address instructions! +// Suprisingly enough, these are not two address instructions! def IMUL16rri : Ii16<0x69, MRMSrcReg, (ops R16:$dst, R16:$src1, i16imm:$src2), "imul $dst, $src1, $src2">, OpSize; // R16 = R16*I16 def IMUL32rri : Ii32<0x69, MRMSrcReg, (ops R32:$dst, R32:$src1, i32imm:$src2), @@ -778,10 +773,15 @@ "imul $dst, $src1, $src2">, OpSize; // R16 = R16*I8 def IMUL32rri8 : Ii8<0x6B, MRMSrcReg, (ops R32:$dst, R32:$src1, i8imm:$src2), "imul $dst, $src1, $src2">; // 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 + +def IMUL16rmi : Ii16<0x69, MRMSrcMem, (ops R32:$dst, i16mem:$src1, i16imm:$src2), + "imul $dst, $src1, $src2">, OpSize; // R16 = [mem16]*I16 +def IMUL32rmi : Ii32<0x69, MRMSrcMem, (ops R32:$dst, i32mem:$src1, i32imm:$src2), + "imul $dst, $src1, $src2">; // R32 = [mem32]*I32 +def IMUL16rmi8 : Ii8<0x6B, MRMSrcMem, (ops R32:$dst, i16mem:$src1, i8imm :$src2), + "imul $dst, $src1, $src2">, OpSize; // R16 = [mem16]*I8 +def IMUL32rmi8 : Ii8<0x6B, MRMSrcMem, (ops R32:$dst, i32mem:$src1, i8imm: $src2), + "imul $dst, $src1, $src2">; // R32 = [mem32]*I8 //===----------------------------------------------------------------------===// // Test instructions are just like AND, except they don't generate a result. @@ -804,15 +804,18 @@ def TEST32rm : I<0x85, MRMSrcMem, (ops R32:$src1, i32mem:$src2), "test $src1, $src2">; -def TEST8ri : Ii8 <0xF6, MRM0r, (ops R8:$dst, i8imm:$src), - "test $dst, $src">; // flags = R8 & imm8 -def TEST16ri : Ii16 <0xF7, MRM0r, (ops R16:$dst, i16imm:$src), - "test $dst, $src">, OpSize; // flags = R16 & imm16 -def TEST32ri : Ii32 <0xF7, MRM0r, (ops R32:$dst, i32imm:$src), - "test $dst, $src">; // 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 +def TEST8ri : Ii8 <0xF6, MRM0r, (ops R8:$dst, i8imm:$src), + "test $dst, $src">; // flags = R8 & imm8 +def TEST16ri : Ii16<0xF7, MRM0r, (ops R16:$dst, i16imm:$src), + "test $dst, $src">, OpSize; // flags = R16 & imm16 +def TEST32ri : Ii32<0xF7, MRM0r, (ops R32:$dst, i32imm:$src), + "test $dst, $src">; // flags = R32 & imm32 +def TEST8mi : Ii8 <0xF6, MRM0m, (ops i32mem:$dst, i8imm:$src), + "test $dst, $src">; // flags = [mem8] & imm8 +def TEST16mi : Ii16<0xF7, MRM0m, (ops i16mem:$dst, i16imm:$src), + "test $dst, $src">, OpSize; // flags = [mem16] & imm16 +def TEST32mi : Ii32<0xF7, MRM0m, (ops i32mem:$dst, i32imm:$src), + "test $dst, $src">; // flags = [mem32] & imm32 @@ -857,12 +860,12 @@ def CMP8rm : I<0x3A, MRMSrcMem , (ops R8 :$src1, i8mem :$src2), "cmp $src1, $src2">; def CMP16rm : I<0x3B, MRMSrcMem , (ops R16:$src1, i16mem:$src2), "cmp $src1, $src2">, OpSize; def CMP32rm : I<0x3B, MRMSrcMem , (ops R32:$src1, i32mem:$src2), "cmp $src1, $src2">; -def CMP8ri : Ii8 <0x80, MRM7r, (ops R16:$dst, i8imm:$src), "cmp $dst, $src">; -def CMP16ri : Ii16 <0x81, MRM7r, (ops R16:$dst, i16imm:$src), "cmp $dst, $src">, OpSize; -def CMP32ri : Ii32 <0x81, MRM7r, (ops R32:$dst, i32imm:$src), "cmp $dst, $src">; -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 +def CMP8ri : Ii8 <0x80, MRM7r, (ops R16:$dst, i8imm:$src), "cmp $dst, $src">; +def CMP16ri : Ii16<0x81, MRM7r, (ops R16:$dst, i16imm:$src), "cmp $dst, $src">, OpSize; +def CMP32ri : Ii32<0x81, MRM7r, (ops R32:$dst, i32imm:$src), "cmp $dst, $src">; +def CMP8mi : Ii8 <0x80, MRM7m, (ops i8mem :$dst, i8imm :$src), "cmp $dst, $src">; +def CMP16mi : Ii16<0x81, MRM7m, (ops i16mem:$dst, i16imm:$src), "cmp $dst, $src">, OpSize; +def CMP32mi : Ii32<0x81, MRM7m, (ops i32mem:$dst, i32imm:$src), "cmp $dst, $src">; // Sign/Zero extenders def MOVSX16rr8 : I<0xBE, MRMSrcReg, (ops R16:$dst, R8 :$src), "movsx $dst, $src">, TB, OpSize; From lattner at cs.uiuc.edu Wed Aug 11 00:54:28 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 00:54:28 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200408110554.AAA27856@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.97 -> 1.98 --- Log message: Make FPI take asm string and operand list --- Diffs of the changes: (+33 -39) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.97 llvm/lib/Target/X86/X86InstrInfo.td:1.98 --- llvm/lib/Target/X86/X86InstrInfo.td:1.97 Wed Aug 11 00:31:07 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Wed Aug 11 00:54:16 2004 @@ -893,7 +893,8 @@ 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<"", o, F, fp, NoMem, NoImm>; +class FPI o, Format F, FPFormat fp, dag ops, string asm> + : FPInst<"", o, F, fp, NoMem, NoImm>, II; class FPIM o, Format F, FPFormat fp, MemType m> : FPInst; @@ -906,14 +907,14 @@ // 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<0, Pseudo, SpecialFP>; // f1 = fmov f2 -def FpADD : FPI<0, Pseudo, TwoArgFP>; // f1 = fadd f2, f3 -def FpSUB : FPI<0, Pseudo, TwoArgFP>; // f1 = fsub f2, f3 -def FpMUL : FPI<0, Pseudo, TwoArgFP>; // f1 = fmul f2, f3 -def FpDIV : FPI<0, Pseudo, TwoArgFP>; // f1 = fdiv f2, f3 +def FpMOV : FPI<0, Pseudo, SpecialFP, (ops RFP, RFP), "">; // f1 = fmov f2 +def FpADD : FPI<0, Pseudo, TwoArgFP , (ops RFP, RFP, RFP), "">; // f1 = fadd f2, f3 +def FpSUB : FPI<0, Pseudo, TwoArgFP , (ops RFP, RFP, RFP), "">; // f1 = fsub f2, f3 +def FpMUL : FPI<0, Pseudo, TwoArgFP , (ops RFP, RFP, RFP), "">; // f1 = fmul f2, f3 +def FpDIV : FPI<0, Pseudo, TwoArgFP , (ops RFP, RFP, RFP), "">; // f1 = fdiv f2, f3 -def FpGETRESULT : FPI<0, Pseudo, SpecialFP>; // FPR = ST(0) -def FpSETRESULT : FPI<0, Pseudo, SpecialFP>; // ST(0) = FPR +def FpGETRESULT : FPI<0, Pseudo, SpecialFP, (ops RFP), "">; // FPR = ST(0) +def FpSETRESULT : FPI<0, Pseudo, SpecialFP, (ops RFP), "">; // ST(0) = FPR // FADD reg, mem: Before stackification, these are represented by: R1 = FADD* R2, [mem] def FADD32m : FPI32m<"fadd", 0xD8, MRM0m, OneArgFPRW>; // ST(0) = ST(0) + [mem32real] @@ -956,23 +957,23 @@ // Floating point cmovs... let isTwoAddress = 1, Uses = [ST0], Defs = [ST0] in { - def FCMOVB : FPI<0xC0, AddRegFrm, CondMovFP>, DA, // fcmovb ST(i) -> ST(0) - II<(ops RST:$op), "fcmovb %ST(0), $op">; - def FCMOVBE : FPI<0xD0, AddRegFrm, CondMovFP>, DA, // fcmovbe ST(i) -> ST(0) - II<(ops RST:$op), "fcmovbe %ST(0), $op">; - def FCMOVE : FPI<0xC8, AddRegFrm, CondMovFP>, DA, // fcmove ST(i) -> ST(0) - II<(ops RST:$op), "fcmove %ST(0), $op">; - def FCMOVAE : FPI<0xC0, AddRegFrm, CondMovFP>, DB, // fcmovae ST(i) -> ST(0) - II<(ops RST:$op), "fcmovae %ST(0), $op">; - def FCMOVA : FPI<0xD0, AddRegFrm, CondMovFP>, DB, // fcmova ST(i) -> ST(0) - II<(ops RST:$op), "fcmova %ST(0), $op">; - def FCMOVNE : FPI<0xC8, AddRegFrm, CondMovFP>, DB, // fcmovne ST(i) -> ST(0) - II<(ops RST:$op), "fcmovne %ST(0), $op">; + def FCMOVB : FPI<0xC0, AddRegFrm, CondMovFP, + (ops RST:$op), "fcmovb %ST(0), $op">, DA; + def FCMOVBE : FPI<0xD0, AddRegFrm, CondMovFP, + (ops RST:$op), "fcmovbe %ST(0), $op">, DA; + def FCMOVE : FPI<0xC8, AddRegFrm, CondMovFP, + (ops RST:$op), "fcmove %ST(0), $op">, DA; + def FCMOVAE : FPI<0xC0, AddRegFrm, CondMovFP, + (ops RST:$op), "fcmovae %ST(0), $op">, DB; + def FCMOVA : FPI<0xD0, AddRegFrm, CondMovFP, + (ops RST:$op), "fcmova %ST(0), $op">, DB; + def FCMOVNE : FPI<0xC8, AddRegFrm, CondMovFP, + (ops RST:$op), "fcmovne %ST(0), $op">, DB; } // Floating point loads & stores... let Name = "fld" in -def FLDrr : FPI<0xC0, AddRegFrm, NotFP>, D9; // push(ST(i)) +def FLDrr : FPI<0xC0, AddRegFrm, NotFP, (ops RST:$op), "fld $op">, D9; 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 @@ -980,10 +981,8 @@ def FILD32m : FPI32m <"fild" , 0xDB, MRM0m , ZeroArgFP>; // load signed int def FILD64m : FPI64m <"fild" , 0xDF, MRM5m , ZeroArgFP>; // load signed long -let Name = "fst" in - def FSTrr : FPI<0xD0, AddRegFrm, NotFP >, DD; // ST(i) = ST(0) -let Name = "fstp" in - def FSTPrr : FPI<0xD8, AddRegFrm, NotFP >, DD; // ST(i) = ST(0), pop +def FSTrr : FPI<0xD0, AddRegFrm, NotFP, (ops RST:$op), "fst $op">, DD; // ST(i) = ST(0) +def FSTPrr : FPI<0xD8, AddRegFrm, NotFP, (ops RST:$op), "fstp $op">, 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 @@ -996,21 +995,16 @@ def FISTP32m : FPI32m <"fistp", 0xDB, MRM3m , NotFP >; // store signed int, pop def FISTP64m : FPI64m <"fistpll", 0xDF, MRM7m , OneArgFP>; // store signed long, pop -def FXCH : FPI<0xC8, AddRegFrm, NotFP>, - II<(ops RST:$op), "fxch $op">, D9; // fxch ST(i), ST(0) +def FXCH : FPI<0xC8, AddRegFrm, NotFP, (ops RST:$op), "fxch $op">, D9; // fxch ST(i), ST(0) // Floating point constant loads... -def FLD0 : FPI<0xEE, RawFrm, ZeroArgFP>, D9, - II<(ops), "fldz">; -def FLD1 : FPI<0xE8, RawFrm, ZeroArgFP>, D9, - II<(ops), "fld1">; +def FLD0 : FPI<0xEE, RawFrm, ZeroArgFP, (ops), "fldz">, D9; +def FLD1 : FPI<0xE8, RawFrm, ZeroArgFP, (ops), "fld1">, D9; // Unary operations... -def FCHS : FPI<0xE0, RawFrm, OneArgFPRW>, // f1 = fchs f2 - II<(ops), "fchs">, D9; -def FTST : FPI<0xE4, RawFrm, OneArgFP>, // ftst ST(0) - II<(ops), "ftst">, D9; +def FCHS : FPI<0xE0, RawFrm, OneArgFPRW, (ops), "fchs">, D9; // f1 = fchs f2 +def FTST : FPI<0xE4, RawFrm, OneArgFP, (ops), "ftst">, D9; // ftst ST(0) // Binary arithmetic operations... class FPST0rInst o, dag ops, string asm> : I, D8 { @@ -1049,15 +1043,15 @@ def FDIVRPrST0 : FPrST0PInst<0xF0, (ops RST:$op), "fdivrp $op">; // ST(i) = ST(0) / ST(i), pop // Floating point compares -def FUCOMr : FPI<0xE0, AddRegFrm, CompareFP>, // FPSW = compare ST(0) with ST(i) - II<(ops RST:$reg), "fucom $reg">, DD, Imp<[ST0],[]>; +def FUCOMr : FPI<0xE0, AddRegFrm, CompareFP, (ops RST:$reg), + "fucom $reg">, DD, Imp<[ST0],[]>; // FPSW = compare ST(0) with ST(i) def FUCOMPr : I<0xE8, AddRegFrm, (ops RST:$reg), "fucomp $reg">, DD, Imp<[ST0],[]>; // FPSW = compare ST(0) with ST(i), pop def FUCOMPPr : I<0xE9, RawFrm, (ops), "fucompp">, DA, Imp<[ST0],[]>; // compare ST(0) with ST(1), pop, pop -def FUCOMIr : FPI<0xE8, AddRegFrm, CompareFP>, // CC = compare ST(0) with ST(i) - II<(ops RST:$reg), "fucomi %ST(0), $reg">, DB, Imp<[ST0],[]>; +def FUCOMIr : FPI<0xE8, AddRegFrm, CompareFP, (ops RST:$reg), + "fucomi %ST(0), $reg">, DB, Imp<[ST0],[]>; // CC = compare ST(0) with ST(i) def FUCOMIPr : I<0xE8, AddRegFrm, (ops RST:$reg), "fucomip %ST(0), $reg">, DF, Imp<[ST0],[]>; // CC = compare ST(0) with ST(i), pop From lattner at cs.uiuc.edu Wed Aug 11 01:10:07 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 01:10:07 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86AsmPrinter.cpp Message-ID: <200408110610.BAA30883@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86AsmPrinter.cpp updated: 1.112 -> 1.113 --- Log message: Move hacks up --- Diffs of the changes: (+30 -32) Index: llvm/lib/Target/X86/X86AsmPrinter.cpp diff -u llvm/lib/Target/X86/X86AsmPrinter.cpp:1.112 llvm/lib/Target/X86/X86AsmPrinter.cpp:1.113 --- llvm/lib/Target/X86/X86AsmPrinter.cpp:1.112 Tue Aug 10 21:25:00 2004 +++ llvm/lib/Target/X86/X86AsmPrinter.cpp Wed Aug 11 01:09:55 2004 @@ -49,7 +49,6 @@ ~GasBugWorkaroundEmitter() { O.flags(OldFlags); - O << "\t# "; } virtual void emitByte(unsigned char B) { @@ -586,6 +585,36 @@ /// void X86AsmPrinter::printMachineInstruction(const MachineInstr *MI) { ++EmittedInsts; + + // gas bugs: + // + // The 80-bit FP store-pop instruction "fstp XWORD PTR [...]" 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. + // + // The 80-bit FP load instruction "fld XWORD PTR [...]" is 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. + // + // gas intel_syntax mode treats "fild QWORD PTR [...]" as an invalid opcode, + // saying "64 bit operations are only supported in 64 bit modes." libopcodes + // disassembles it as "fild DWORD PTR [...]", which is wrong. Workaround: + // Output the raw opcode bytes instead of the instruction. + // + // gas intel_syntax mode treats "fistp QWORD PTR [...]" as an invalid opcode, + // saying "64 bit operations are only supported in 64 bit modes." libopcodes + // disassembles it as "fistpll DWORD PTR [...]", which is wrong. Workaround: + // Output the raw opcode bytes instead of the instruction. + switch (MI->getOpcode()) { + case X86::FSTP80m: + case X86::FLD80m: + case X86::FILD64m: + case X86::FISTP64m: + GasBugWorkaroundEmitter gwe(O); + X86::emitInstruction(gwe, (X86InstrInfo&)*TM.getInstrInfo(), *MI); + O << "\t# "; + } + if (printInstruction(MI)) return; // Printer was automatically generated @@ -853,37 +882,6 @@ const MachineOperand &Op3 = MI->getOperand(3); - // gas bugs: - // - // The 80-bit FP store-pop instruction "fstp XWORD PTR [...]" - // 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. - // - // The 80-bit FP load instruction "fld XWORD PTR [...]" is - // 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. - // - // gas intel_syntax mode treats "fild QWORD PTR [...]" as an - // invalid opcode, saying "64 bit operations are only supported in - // 64 bit modes." libopcodes disassembles it as "fild DWORD PTR - // [...]", which is wrong. Workaround: Output the raw opcode bytes - // instead of the instruction. - // - // gas intel_syntax mode treats "fistp QWORD PTR [...]" as an - // invalid opcode, saying "64 bit operations are only supported in - // 64 bit modes." libopcodes disassembles it as "fistpll DWORD PTR - // [...]", which is wrong. Workaround: Output the raw opcode bytes - // instead of the instruction. - if (MI->getOpcode() == X86::FSTP80m || - MI->getOpcode() == X86::FLD80m || - MI->getOpcode() == X86::FILD64m || - MI->getOpcode() == X86::FISTP64m) { - GasBugWorkaroundEmitter gwe(O); - X86::emitInstruction(gwe, (X86InstrInfo&)*TM.getInstrInfo(), *MI); - } - O << TII.getName(MI->getOpcode()) << " "; O << sizePtr(Desc) << " "; printMemReference(MI, 0); From lattner at cs.uiuc.edu Wed Aug 11 01:50:23 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 01:50:23 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td Message-ID: <200408110650.BAA00736@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.98 -> 1.99 --- Log message: Scrunch memoperands, add a few more for floating point memops Eliminate the FPI*m classes, converting them to use FPI instead. --- Diffs of the changes: (+61 -68) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.98 llvm/lib/Target/X86/X86InstrInfo.td:1.99 --- llvm/lib/Target/X86/X86InstrInfo.td:1.98 Wed Aug 11 00:54:16 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Wed Aug 11 01:50:10 2004 @@ -15,21 +15,19 @@ // *mem - Operand definitions for the funky X86 addressing mode operands. // -def i8mem : Operand { - let NumMIOperands = 4; - let PrintMethod = "printMemoryOperand"; -} -def i16mem : Operand { - let NumMIOperands = 4; - let PrintMethod = "printMemoryOperand"; -} - -def i32mem : Operand { +class X86MemOperand : Operand { let NumMIOperands = 4; let PrintMethod = "printMemoryOperand"; } +def i8mem : X86MemOperand; +def i16mem : X86MemOperand; +def i32mem : X86MemOperand; +def i64mem : X86MemOperand; +def f32mem : X86MemOperand; +def f64mem : X86MemOperand; +def f80mem : X86MemOperand; // Format specifies the encoding used by the instruction. This is part of the // ad-hoc solution used to emit machine instruction encodings by our machine @@ -889,19 +887,11 @@ // FIXME: These need to indicate mod/ref sets for FP regs... & FP 'TOP' -// Floating point instruction templates -class FPInst o, Format F, FPFormat fp, MemType m, ImmType i> - : X86Inst { let FPForm = fp; let FPFormBits = FPForm.Value; } - +// Floating point instruction template class FPI o, Format F, FPFormat fp, dag ops, string asm> - : FPInst<"", o, F, fp, NoMem, NoImm>, II; - -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; + : X86Inst<"", o, F, NoMem, NoImm>, II { + let FPForm = fp; let FPFormBits = FPForm.Value; +} // Pseudo instructions for floating point. We use these pseudo instructions // because they can be expanded by the fp spackifier into one of many different @@ -917,42 +907,46 @@ def FpSETRESULT : FPI<0, Pseudo, SpecialFP, (ops RFP), "">; // ST(0) = FPR // FADD reg, mem: Before stackification, these are represented by: R1 = FADD* R2, [mem] -def FADD32m : FPI32m<"fadd", 0xD8, MRM0m, OneArgFPRW>; // ST(0) = ST(0) + [mem32real] -def FADD64m : FPI64m<"fadd", 0xDC, MRM0m, OneArgFPRW>; // ST(0) = ST(0) + [mem64real] -def FIADD16m : FPI16m<"fiadd", 0xDE, MRM0m, OneArgFPRW>; // ST(0) = ST(0) + [mem16int] -def FIADD32m : FPI32m<"fiadd", 0xDA, MRM0m, OneArgFPRW>; // ST(0) = ST(0) + [mem32int] +def FADD32m : FPI<0xD8, MRM0m, OneArgFPRW, (ops f32mem:$src), "fadd $src">; // ST(0) = ST(0) + [mem32real] +def FADD64m : FPI<0xDC, MRM0m, OneArgFPRW, (ops f64mem:$src), "fadd $src">; // ST(0) = ST(0) + [mem64real] +/* +def FIADD16m : FPI<0xDE, MRM0m, OneArgFPRW, (ops i16mem:$src), // ST(0) = ST(0) + [mem16int] + "fiadd $src">; +def FIADD32m : FPI<0xDA, MRM0m, OneArgFPRW, (ops i32mem:$src), // ST(0) = ST(0) + [mem32int] + "fiadd $src">; +*/ // FMUL reg, mem: Before stackification, these are represented by: R1 = FMUL* R2, [mem] -def FMUL32m : FPI32m<"fmul", 0xD8, MRM1m, OneArgFPRW>; // ST(0) = ST(0) * [mem32real] -def FMUL64m : FPI64m<"fmul", 0xDC, MRM1m, OneArgFPRW>; // ST(0) = ST(0) * [mem64real] -def FIMUL16m : FPI16m<"fimul", 0xDE, MRM1m, OneArgFPRW>; // ST(0) = ST(0) * [mem16int] -def FIMUL32m : FPI32m<"fimul", 0xDA, MRM1m, OneArgFPRW>; // ST(0) = ST(0) * [mem32int] +def FMUL32m : FPI<0xD8, MRM1m, OneArgFPRW, (ops f32mem:$src), "fmul $src">; // ST(0) = ST(0) * [mem32real] +def FMUL64m : FPI<0xDC, MRM1m, OneArgFPRW, (ops f64mem:$src), "fmul $src">; // ST(0) = ST(0) * [mem64real] +//def FIMUL16m : FPI16m<"fimul", 0xDE, MRM1m, OneArgFPRW>; // ST(0) = ST(0) * [mem16int] +//def FIMUL32m : FPI32m<"fimul", 0xDA, MRM1m, OneArgFPRW>; // ST(0) = ST(0) * [mem32int] // FSUB reg, mem: Before stackification, these are represented by: R1 = FSUB* R2, [mem] -def FSUB32m : FPI32m<"fsub", 0xD8, MRM4m, OneArgFPRW>; // ST(0) = ST(0) - [mem32real] -def FSUB64m : FPI64m<"fsub", 0xDC, MRM4m, OneArgFPRW>; // ST(0) = ST(0) - [mem64real] -def FISUB16m : FPI16m<"fisub", 0xDE, MRM4m, OneArgFPRW>; // ST(0) = ST(0) - [mem16int] -def FISUB32m : FPI32m<"fisub", 0xDA, MRM4m, OneArgFPRW>; // ST(0) = ST(0) - [mem32int] +def FSUB32m : FPI<0xD8, MRM4m, OneArgFPRW, (ops f32mem:$src), "fsub $src">; // ST(0) = ST(0) - [mem32real] +def FSUB64m : FPI<0xDC, MRM4m, OneArgFPRW, (ops f64mem:$src), "fsub $src">; // ST(0) = ST(0) - [mem64real] +//def FISUB16m : FPI16m<"fisub", 0xDE, MRM4m, OneArgFPRW>; // ST(0) = ST(0) - [mem16int] +//def FISUB32m : FPI32m<"fisub", 0xDA, MRM4m, OneArgFPRW>; // ST(0) = ST(0) - [mem32int] // FSUBR reg, mem: Before stackification, these are represented by: R1 = FSUBR* R2, [mem] // Note that the order of operands does not reflect the operation being performed. -def FSUBR32m : FPI32m<"fsubr", 0xD8, MRM5m, OneArgFPRW>; // ST(0) = [mem32real] - ST(0) -def FSUBR64m : FPI64m<"fsubr", 0xDC, MRM5m, OneArgFPRW>; // ST(0) = [mem64real] - ST(0) -def FISUBR16m : FPI16m<"fisubr", 0xDE, MRM5m, OneArgFPRW>; // ST(0) = [mem16int] - ST(0) -def FISUBR32m : FPI32m<"fisubr", 0xDA, MRM5m, OneArgFPRW>; // ST(0) = [mem32int] - ST(0) +def FSUBR32m : FPI<0xD8, MRM5m, OneArgFPRW, (ops f32mem:$src), "fsubr $src">; // ST(0) = [mem32real] - ST(0) +def FSUBR64m : FPI<0xDC, MRM5m, OneArgFPRW, (ops f64mem:$src), "fsubr $src">; // ST(0) = [mem64real] - ST(0) +//def FISUBR16m : FPI16m<"fisubr", 0xDE, MRM5m, OneArgFPRW>; // ST(0) = [mem16int] - ST(0) +//def FISUBR32m : FPI32m<"fisubr", 0xDA, MRM5m, OneArgFPRW>; // ST(0) = [mem32int] - ST(0) // FDIV reg, mem: Before stackification, these are represented by: R1 = FDIV* R2, [mem] -def FDIV32m : FPI32m<"fdiv", 0xD8, MRM6m, OneArgFPRW>; // ST(0) = ST(0) / [mem32real] -def FDIV64m : FPI64m<"fdiv", 0xDC, MRM6m, OneArgFPRW>; // ST(0) = ST(0) / [mem64real] -def FIDIV16m : FPI16m<"fidiv", 0xDE, MRM6m, OneArgFPRW>; // ST(0) = ST(0) / [mem16int] -def FIDIV32m : FPI32m<"fidiv", 0xDA, MRM6m, OneArgFPRW>; // ST(0) = ST(0) / [mem32int] +def FDIV32m : FPI<0xD8, MRM6m, OneArgFPRW, (ops f32mem:$src), "fdiv $src">; // ST(0) = ST(0) / [mem32real] +def FDIV64m : FPI<0xDC, MRM6m, OneArgFPRW, (ops f64mem:$src), "fdiv $src">; // ST(0) = ST(0) / [mem64real] +//def FIDIV16m : FPI16m<"fidiv", 0xDE, MRM6m, OneArgFPRW>; // ST(0) = ST(0) / [mem16int] +//def FIDIV32m : FPI32m<"fidiv", 0xDA, MRM6m, OneArgFPRW>; // ST(0) = ST(0) / [mem32int] // FDIVR reg, mem: Before stackification, these are represented by: R1 = FDIVR* R2, [mem] // Note that the order of operands does not reflect the operation being performed. -def FDIVR32m : FPI32m<"fdivr", 0xD8, MRM7m, OneArgFPRW>; // ST(0) = [mem32real] / ST(0) -def FDIVR64m : FPI64m<"fdivr", 0xDC, MRM7m, OneArgFPRW>; // ST(0) = [mem64real] / ST(0) -def FIDIVR16m : FPI16m<"fidivr", 0xDE, MRM7m, OneArgFPRW>; // ST(0) = [mem16int] / ST(0) -def FIDIVR32m : FPI32m<"fidivr", 0xDA, MRM7m, OneArgFPRW>; // ST(0) = [mem32int] / ST(0) +def FDIVR32m : FPI<0xD8, MRM7m, OneArgFPRW, (ops f32mem:$src), "fdivr $src">; // ST(0) = [mem32real] / ST(0) +def FDIVR64m : FPI<0xDC, MRM7m, OneArgFPRW, (ops f64mem:$src), "fdivr $src">; // ST(0) = [mem64real] / ST(0) +//def FIDIVR16m : FPI16m<"fidivr", 0xDE, MRM7m, OneArgFPRW>; // ST(0) = [mem16int] / ST(0) +//def FIDIVR32m : FPI32m<"fidivr", 0xDA, MRM7m, OneArgFPRW>; // ST(0) = [mem32int] / ST(0) // Floating point cmovs... @@ -972,28 +966,27 @@ } // Floating point loads & stores... -let Name = "fld" in -def FLDrr : FPI<0xC0, AddRegFrm, NotFP, (ops RST:$op), "fld $op">, D9; -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<0xD0, AddRegFrm, NotFP, (ops RST:$op), "fst $op">, DD; // ST(i) = ST(0) -def FSTPrr : FPI<0xD8, AddRegFrm, NotFP, (ops RST:$op), "fstp $op">, 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 FLDrr : FPI<0xC0, AddRegFrm, NotFP, (ops RST:$src), "fld $src">, D9; +def FLD32m : FPI<0xD9, MRM0m, ZeroArgFP, (ops f32mem:$src), "fld $src">; +def FLD64m : FPI<0xDD, MRM0m, ZeroArgFP, (ops f64mem:$src), "fld $src">; +def FLD80m : FPI<0xDB, MRM5m, ZeroArgFP, (ops f80mem:$src), "fld $src">; +def FILD16m : FPI<0xDF, MRM0m, ZeroArgFP, (ops i16mem:$src), "fild $src">; +def FILD32m : FPI<0xDB, MRM0m, ZeroArgFP, (ops i32mem:$src), "fild $src">; +def FILD64m : FPI<0xDF, MRM5m, ZeroArgFP, (ops i64mem:$src), "fild $src">; + +def FSTrr : FPI<0xD0, AddRegFrm, NotFP, (ops RST:$op), "fst $op">, DD; +def FSTPrr : FPI<0xD8, AddRegFrm, NotFP, (ops RST:$op), "fstp $op">, DD; +def FST32m : FPI<0xD9, MRM2m, OneArgFP, (ops f32mem:$op), "fst $op">; +def FST64m : FPI<0xDD, MRM2m, OneArgFP, (ops f64mem:$op), "fst $op">; +def FSTP32m : FPI<0xD9, MRM3m, OneArgFP, (ops f32mem:$op), "fstp $op">; +def FSTP64m : FPI<0xDD, MRM3m, OneArgFP, (ops f64mem:$op), "fstp $op">; +def FSTP80m : FPI<0xDB, MRM7m, OneArgFP, (ops f80mem:$op), "fstp $op">; + +def FIST16m : FPI<0xDF, MRM2m , OneArgFP, (ops i16mem:$op), "fist $op">; +def FIST32m : FPI<0xDB, MRM2m , OneArgFP, (ops i32mem:$op), "fist $op">; +def FISTP16m : FPI<0xDF, MRM3m , NotFP , (ops i16mem:$op), "fistp $op">; +def FISTP32m : FPI<0xDB, MRM3m , NotFP , (ops i32mem:$op), "fistp $op">; +def FISTP64m : FPI<0xDF, MRM7m , OneArgFP, (ops i64mem:$op), "fistpll $op">; def FXCH : FPI<0xC8, AddRegFrm, NotFP, (ops RST:$op), "fxch $op">, D9; // fxch ST(i), ST(0) From lattner at cs.uiuc.edu Wed Aug 11 01:55:24 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 01:55:24 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrSelInfo.td Message-ID: <200408110655.BAA02268@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrSelInfo.td (r1.1) removed --- Log message: This file is long dead --- Diffs of the changes: (+0 -0) From lattner at cs.uiuc.edu Wed Aug 11 01:59:24 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 01:59:24 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86AsmPrinter.cpp X86InstrInfo.td Message-ID: <200408110659.BAA03587@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86AsmPrinter.cpp updated: 1.113 -> 1.114 X86InstrInfo.td updated: 1.99 -> 1.100 --- Log message: Add asmprintergen support for the last X86 instruction that needs it: pcrelative calls. --- Diffs of the changes: (+12 -1) Index: llvm/lib/Target/X86/X86AsmPrinter.cpp diff -u llvm/lib/Target/X86/X86AsmPrinter.cpp:1.113 llvm/lib/Target/X86/X86AsmPrinter.cpp:1.114 --- llvm/lib/Target/X86/X86AsmPrinter.cpp:1.113 Wed Aug 11 01:09:55 2004 +++ llvm/lib/Target/X86/X86AsmPrinter.cpp Wed Aug 11 01:59:12 2004 @@ -115,6 +115,10 @@ } } + void printCallOperand(const MachineInstr *MI, unsigned OpNo, MVT::ValueType VT) { + printOp(MI->getOperand(OpNo), true); // Don't print "OFFSET". + } + void printMemoryOperand(const MachineInstr *MI, unsigned OpNo, MVT::ValueType VT) { switch (VT) { @@ -618,6 +622,9 @@ if (printInstruction(MI)) return; // Printer was automatically generated + MI->dump(); + abort(); + unsigned Opcode = MI->getOpcode(); const TargetInstrInfo &TII = *TM.getInstrInfo(); const TargetInstrDescriptor &Desc = TII.get(Opcode); Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.99 llvm/lib/Target/X86/X86InstrInfo.td:1.100 --- llvm/lib/Target/X86/X86InstrInfo.td:1.99 Wed Aug 11 01:50:10 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Wed Aug 11 01:59:12 2004 @@ -29,6 +29,10 @@ def f64mem : X86MemOperand; def f80mem : X86MemOperand; +// PCRelative calls need special operand formatting. +let PrintMethod = "printCallOperand" in + def calltarget : Operand; + // Format specifies the encoding used by the instruction. This is part of the // ad-hoc solution used to emit machine instruction encodings by our machine // code emitter. @@ -196,7 +200,7 @@ 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, NoMem, NoImm>; // FIXME: 'call' doesn't allow 'OFFSET' + def CALLpcrel32 : I<0xE8, RawFrm, (ops calltarget:$dst), "call $dst">; def CALL32r : I<0xFF, MRM2r, (ops R32:$dst), "call $dst">; def CALL32m : I<0xFF, MRM2m, (ops i32mem:$dst), "call $dst">; } From lattner at cs.uiuc.edu Wed Aug 11 02:02:16 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 02:02:16 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86AsmPrinter.cpp Message-ID: <200408110702.CAA03614@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86AsmPrinter.cpp updated: 1.114 -> 1.115 --- Log message: Finally, the entire instruction asmprinter is now generated from tblgen, woo! --- Diffs of the changes: (+8 -296) Index: llvm/lib/Target/X86/X86AsmPrinter.cpp diff -u llvm/lib/Target/X86/X86AsmPrinter.cpp:1.114 llvm/lib/Target/X86/X86AsmPrinter.cpp:1.115 --- llvm/lib/Target/X86/X86AsmPrinter.cpp:1.114 Wed Aug 11 01:59:12 2004 +++ llvm/lib/Target/X86/X86AsmPrinter.cpp Wed Aug 11 02:02:04 2004 @@ -438,8 +438,8 @@ if (MI->getOperand(Op).isFrameIndex()) return true; if (MI->getOperand(Op).isConstantPoolIndex()) return true; return Op+4 <= MI->getNumOperands() && - MI->getOperand(Op ).isRegister() &&isScale(MI->getOperand(Op+1)) && - MI->getOperand(Op+2).isRegister() &&MI->getOperand(Op+3).isImmediate(); + MI->getOperand(Op ).isRegister() && isScale(MI->getOperand(Op+1)) && + MI->getOperand(Op+2).isRegister() && MI->getOperand(Op+3).isImmediate(); } @@ -490,17 +490,6 @@ } } -static const char* const sizePtr(const TargetInstrDescriptor &Desc) { - switch (Desc.TSFlags & X86II::MemMask) { - default: assert(0 && "Unknown arg size!"); - 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"; - } -} - void X86AsmPrinter::printMemReference(const MachineInstr *MI, unsigned Op) { assert(isMem(MI, Op) && "Invalid memory reference!"); @@ -619,289 +608,12 @@ O << "\t# "; } - if (printInstruction(MI)) - return; // Printer was automatically generated - - MI->dump(); - abort(); - - unsigned Opcode = MI->getOpcode(); - const TargetInstrInfo &TII = *TM.getInstrInfo(); - const TargetInstrDescriptor &Desc = TII.get(Opcode); - - switch (Desc.TSFlags & X86II::FormMask) { - case X86II::Pseudo: - // Print pseudo-instructions as comments; either they should have been - // turned into real instructions by now, or they don't need to be - // seen by the assembler (e.g., IMPLICIT_USEs.) - O << "# "; - if (Opcode == X86::PHI) { - printOp(MI->getOperand(0)); - O << " = phi "; - for (unsigned i = 1, e = MI->getNumOperands(); i != e; i+=2) { - if (i != 1) O << ", "; - O << "["; - printOp(MI->getOperand(i)); - O << ", "; - printOp(MI->getOperand(i+1)); - O << "]"; - } - } else { - unsigned i = 0; - if (MI->getNumOperands() && MI->getOperand(0).isDef()) { - printOp(MI->getOperand(0)); - O << " = "; - ++i; - } - O << TII.getName(MI->getOpcode()); - - for (unsigned e = MI->getNumOperands(); i != e; ++i) { - O << " "; - if (MI->getOperand(i).isDef()) O << "*"; - printOp(MI->getOperand(i)); - if (MI->getOperand(i).isDef()) O << "*"; - } - } - O << "\n"; - return; - - case X86II::RawFrm: - { - // The accepted forms of Raw instructions are: - // 1. jmp foo - MachineBasicBlock operand - // 2. call bar - GlobalAddress Operand or External Symbol Operand - // 3. in AL, imm - Immediate operand - // - assert(MI->getNumOperands() == 1 && - (MI->getOperand(0).isMachineBasicBlock() || - MI->getOperand(0).isGlobalAddress() || - MI->getOperand(0).isExternalSymbol() || - MI->getOperand(0).isImmediate()) && - "Illegal raw instruction!"); - O << TII.getName(MI->getOpcode()) << " "; - - bool LeadingComma = false; - if (MI->getNumOperands() == 1) { - printOp(MI->getOperand(0), true); // Don't print "OFFSET"... - LeadingComma = true; - } - printImplUsesAfter(Desc, LeadingComma); - O << "\n"; - return; - } - - case X86II::AddRegFrm: { - // There are currently two forms of acceptable AddRegFrm instructions. - // Either the instruction JUST takes a single register (like inc, dec, etc), - // or it takes a register and an immediate of the same size as the register - // (move immediate f.e.). Note that this immediate value might be stored as - // an LLVM value, to represent, for example, loading the address of a global - // into a register. The initial register might be duplicated if this is a - // M_2_ADDR_REG instruction - // - assert(MI->getOperand(0).isRegister() && - (MI->getNumOperands() == 1 || - (MI->getNumOperands() == 2 && - (MI->getOperand(1).getVRegValueOrNull() || - MI->getOperand(1).isImmediate() || - MI->getOperand(1).isRegister() || - MI->getOperand(1).isGlobalAddress() || - MI->getOperand(1).isExternalSymbol()))) && - "Illegal form for AddRegFrm instruction!"); - - unsigned Reg = MI->getOperand(0).getReg(); - - O << TII.getName(MI->getOpcode()) << " "; - - printOp(MI->getOperand(0)); - if (MI->getNumOperands() == 2 && - (!MI->getOperand(1).isRegister() || - MI->getOperand(1).getVRegValueOrNull() || - MI->getOperand(1).isGlobalAddress() || - MI->getOperand(1).isExternalSymbol())) { - O << ", "; - printOp(MI->getOperand(1)); - } - printImplUsesAfter(Desc); - O << "\n"; - return; - } - case X86II::MRMDestReg: { - // 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: two address instructions which def&use the first - // argument and use the second as input. - // - // 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 || - (MI->getNumOperands() == 3 && MI->getOperand(2).isImmediate())) - && "Bad format for MRMDestReg!"); - - O << TII.getName(MI->getOpcode()) << " "; - printOp(MI->getOperand(0)); - O << ", "; - printOp(MI->getOperand(1)); - if (MI->getNumOperands() == 3) { - O << ", "; - printOp(MI->getOperand(2)); - } - printImplUsesAfter(Desc); - O << "\n"; - return; - } - - case X86II::MRMDestMem: { - // 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->getNumOperands() == 4+2 && MI->getOperand(5).isImmediate())) - && "Bad format for MRMDestMem!"); - - 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)); - } - printImplUsesAfter(Desc); - O << "\n"; - return; - } - - case X86II::MRMSrcReg: { - // There are three forms that are acceptable for MRMSrcReg - // instructions, those with 2 or 3 operands: - // - // 2 Operands: this is for things like mov that do not read a - // second input. - // - // 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. - // - // - assert(MI->getOperand(0).isRegister() && - MI->getOperand(1).isRegister() && - (MI->getNumOperands() == 2 || - (MI->getNumOperands() == 3 && - (MI->getOperand(2).isImmediate()))) - && "Bad format for MRMSrcReg!"); - - O << TII.getName(MI->getOpcode()) << " "; - printOp(MI->getOperand(0)); - O << ", "; - printOp(MI->getOperand(1)); - if (MI->getNumOperands() == 3) { - O << ", "; - printOp(MI->getOperand(2)); - } - O << "\n"; - return; - } - - case X86II::MRMSrcMem: { - // These instructions are the same as MRMSrcReg, but instead of having a - // register reference for the mod/rm field, it's a memory reference. - // - assert(MI->getOperand(0).isRegister() && - ((MI->getNumOperands() == 1+4 && isMem(MI, 1)) || - (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, 1); - if (MI->getNumOperands() == 2+4) { - O << ", "; - printOp(MI->getOperand(5)); - } - O << "\n"; - return; - } - - 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 - // 2. shl rdest, rinput - // 3. sbb rdest, rinput, immediate [rdest = rinput] - // - assert(MI->getNumOperands() > 0 && MI->getNumOperands() < 4 && - MI->getOperand(0).isRegister() && "Bad MRMSxR format!"); - assert((MI->getNumOperands() != 2 || - MI->getOperand(1).isRegister() || MI->getOperand(1).isImmediate())&& - "Bad MRMSxR format!"); - assert((MI->getNumOperands() < 3 || - (MI->getOperand(1).isRegister() && MI->getOperand(2).isImmediate())) && - "Bad MRMSxR format!"); - - if (MI->getNumOperands() > 1 && MI->getOperand(1).isRegister() && - MI->getOperand(0).getReg() != MI->getOperand(1).getReg()) - O << "**"; - - O << TII.getName(MI->getOpcode()) << " "; - printOp(MI->getOperand(0)); - if (MI->getOperand(MI->getNumOperands()-1).isImmediate()) { - O << ", "; - printOp(MI->getOperand(MI->getNumOperands()-1)); - } - printImplUsesAfter(Desc); - O << "\n"; - - return; - } - - 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 - // 2. shl [m], rinput - // 3. sbb [m], immediate - // - assert(MI->getNumOperands() >= 4 && MI->getNumOperands() <= 5 && - isMem(MI, 0) && "Bad MRMSxM format!"); - assert((MI->getNumOperands() != 5 || - (MI->getOperand(4).isImmediate() || - MI->getOperand(4).isGlobalAddress())) && - "Bad MRMSxM format!"); - - const MachineOperand &Op3 = MI->getOperand(3); - - O << TII.getName(MI->getOpcode()) << " "; - O << sizePtr(Desc) << " "; - printMemReference(MI, 0); - if (MI->getNumOperands() == 5) { - O << ", "; - printOp(MI->getOperand(4)); - } - printImplUsesAfter(Desc); - O << "\n"; - return; - } - default: - O << "\tUNKNOWN FORM:\t\t-"; MI->print(O, &TM); break; + // Call the autogenerated instruction printer routines. + bool Handled = printInstruction(MI); + if (!Handled) { + MI->dump(); + assert(0 && "Do not know how to print this instruction!"); + abort(); } } From lattner at cs.uiuc.edu Wed Aug 11 02:07:26 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 02:07:26 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86AsmPrinter.cpp Message-ID: <200408110707.CAA04813@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86AsmPrinter.cpp updated: 1.115 -> 1.116 --- Log message: Remove a dead method --- Diffs of the changes: (+0 -32) Index: llvm/lib/Target/X86/X86AsmPrinter.cpp diff -u llvm/lib/Target/X86/X86AsmPrinter.cpp:1.115 llvm/lib/Target/X86/X86AsmPrinter.cpp:1.116 --- llvm/lib/Target/X86/X86AsmPrinter.cpp:1.115 Wed Aug 11 02:02:04 2004 +++ llvm/lib/Target/X86/X86AsmPrinter.cpp Wed Aug 11 02:07:14 2004 @@ -134,7 +134,6 @@ printMemReference(MI, OpNo); } - bool printImplUsesAfter(const TargetInstrDescriptor &Desc, const bool LC); void printMachineInstruction(const MachineInstr *MI); void printOp(const MachineOperand &MO, bool elideOffsetKeyword = false); void printMemReference(const MachineInstr *MI, unsigned Op); @@ -541,37 +540,6 @@ O << "]"; } -/// printImplUsesAfter - Emit the implicit-use registers for the instruction -/// described by DESC, if its PrintImplUsesAfter flag is set. -/// -/// Inputs: -/// Comma - List of registers will need a leading comma. -/// Desc - Description of the Instruction. -/// -/// Return value: -/// true - Emitted one or more registers. -/// false - Emitted no registers. -/// -bool X86AsmPrinter::printImplUsesAfter(const TargetInstrDescriptor &Desc, - const bool Comma = true) { - const MRegisterInfo &RI = *TM.getRegisterInfo(); - if (Desc.TSFlags & X86II::PrintImplUsesAfter) { - bool emitted = false; - const unsigned *p = Desc.ImplicitUses; - if (*p) { - O << (Comma ? ", %" : "%") << RI.get (*p).Name; - emitted = true; - ++p; - } - while (*p) { - // Bug Workaround: See note in X86AsmPrinter::doInitialization about %. - O << ", %" << RI.get(*p).Name; - ++p; - } - return emitted; - } - return false; -} /// printMachineInstruction -- Print out a single X86 LLVM instruction /// MI in Intel syntax to the current output stream. From lattner at cs.uiuc.edu Wed Aug 11 02:12:19 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 02:12:19 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/X86/X86InstrInfo.td X86.td X86InstrInfo.h Message-ID: <200408110712.CAA06270@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/X86: X86InstrInfo.td updated: 1.100 -> 1.101 X86.td updated: 1.12 -> 1.13 X86InstrInfo.h updated: 1.42 -> 1.43 --- Log message: Remove a bunch of ad-hoc target-specific flags that were only used by the old asmprinter. --- Diffs of the changes: (+16 -57) Index: llvm/lib/Target/X86/X86InstrInfo.td diff -u llvm/lib/Target/X86/X86InstrInfo.td:1.100 llvm/lib/Target/X86/X86InstrInfo.td:1.101 --- llvm/lib/Target/X86/X86InstrInfo.td:1.100 Wed Aug 11 01:59:12 2004 +++ llvm/lib/Target/X86/X86InstrInfo.td Wed Aug 11 02:12:02 2004 @@ -62,18 +62,6 @@ 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 NoMem : MemType<0>; -def Mem16 : MemType<2>; -def Mem32 : MemType<3>; -def Mem64 : MemType<4>; -def Mem80 : MemType<5>; - // FPFormat - This specifies what form this FP instruction has. This is used by // the Floating-Point stackifier pass. class FPFormat val> { @@ -89,26 +77,23 @@ def SpecialFP : FPFormat<7>; -class X86Inst opcod, Format f, MemType m, ImmType i> : Instruction { +class X86Inst opcod, Format f, ImmType i, dag ops, string AsmStr> : Instruction { let Namespace = "X86"; - let Name = nam; bits<8> Opcode = opcod; Format Form = f; bits<5> FormBits = Form.Value; - MemType MemT = m; - bits<3> MemTypeBits = MemT.Value; ImmType ImmT = i; bits<2> ImmTypeBits = ImmT.Value; + dag OperandList = ops; + string AsmString = AsmStr; + // // Attributes specific to X86 instructions... // bit hasOpSizePrefix = 0; // Does this inst have a 0x66 prefix? - // Flag whether implicit register usage is printed after the instruction. - bit printImplicitUsesAfter = 0; - bits<4> Prefix = 0; // Which prefix byte does this inst have? FPFormat FPForm; // What flavor of FP instruction is this? bits<3> FPFormBits = 0; @@ -119,12 +104,6 @@ list Defs = defs; } -// II - InstructionInfo - this will eventually replace the I class. -class II { - dag OperandList = ops; - string AsmString = AsmStr; -} - // Prefix byte classes which are used to indicate to the ad-hoc machine code // emitter that various prefix bytes are required. @@ -144,12 +123,11 @@ //===----------------------------------------------------------------------===// // Instruction templates... -class I o, Format f, dag ops, string asm> : X86Inst<"", o, f, NoMem, NoImm>, II; +class I o, Format f, dag ops, string asm> : X86Inst; -class Ii o, Format f, ImmType i> : X86Inst<"", o, f, NoMem, i>; -class Ii8 o, Format f, dag ops, string asm> : Ii, II; -class Ii16 o, Format f, dag ops, string asm> : Ii, II; -class Ii32 o, Format f, dag ops, string asm> : Ii, II; +class Ii8 o, Format f, dag ops, string asm> : X86Inst; +class Ii16 o, Format f, dag ops, string asm> : X86Inst; +class Ii32 o, Format f, dag ops, string asm> : X86Inst; //===----------------------------------------------------------------------===// // Instruction list... @@ -893,7 +871,7 @@ // Floating point instruction template class FPI o, Format F, FPFormat fp, dag ops, string asm> - : X86Inst<"", o, F, NoMem, NoImm>, II { + : X86Inst { let FPForm = fp; let FPFormBits = FPForm.Value; } Index: llvm/lib/Target/X86/X86.td diff -u llvm/lib/Target/X86/X86.td:1.12 llvm/lib/Target/X86/X86.td:1.13 --- llvm/lib/Target/X86/X86.td:1.12 Sun Aug 1 03:23:17 2004 +++ llvm/lib/Target/X86/X86.td Wed Aug 11 02:12:03 2004 @@ -36,19 +36,15 @@ let TSFlagsFields = ["FormBits", "hasOpSizePrefix", "Prefix", - "MemTypeBits", "ImmTypeBits", "FPFormBits", - "printImplicitUsesAfter", "Opcode"]; let TSFlagsShifts = [0, 5, 6, 10, - 13, - 15, - 18, - 19]; + 12, + 16]; } def X86 : Target { Index: llvm/lib/Target/X86/X86InstrInfo.h diff -u llvm/lib/Target/X86/X86InstrInfo.h:1.42 llvm/lib/Target/X86/X86InstrInfo.h:1.43 --- llvm/lib/Target/X86/X86InstrInfo.h:1.42 Sun Aug 1 03:23:17 2004 +++ llvm/lib/Target/X86/X86InstrInfo.h Wed Aug 11 02:12:04 2004 @@ -109,21 +109,9 @@ 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. - MemShift = 10, - MemMask = 7 << MemShift, - Mem8 = 1 << MemShift, - Mem16 = 2 << MemShift, - Mem32 = 3 << MemShift, - Mem64 = 4 << MemShift, - Mem80 = 5 << MemShift, - Mem128 = 6 << MemShift, - - //===------------------------------------------------------------------===// // This two-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, + ImmShift = 10, ImmMask = 7 << ImmShift, Imm8 = 1 << ImmShift, Imm16 = 2 << ImmShift, @@ -133,7 +121,7 @@ // FP Instruction Classification... Zero is non-fp instruction. // FPTypeMask - Mask for all of the FP types... - FPTypeShift = 15, + FPTypeShift = 12, FPTypeMask = 7 << FPTypeShift, // NotFP - The default, set for instructions that do not use FP registers. @@ -165,13 +153,10 @@ // SpecialFP - Special instruction forms. Dispatch by opcode explicitly. SpecialFP = 7 << FPTypeShift, - // PrintImplUsesAfter - Print out implicit uses in the assembly output after - // the normal operands. - PrintImplUsesAfter = 1 << 18, - - OpcodeShift = 19, + // Bit 15 is unused. + OpcodeShift = 16, OpcodeMask = 0xFF << OpcodeShift, - // Bits 27 -> 31 are unused + // Bits 24 -> 31 are unused }; } From lattner at cs.uiuc.edu Wed Aug 11 02:35:12 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 02:35:12 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp Message-ID: <200408110735.CAA17192@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC32ISelSimple.cpp updated: 1.58 -> 1.59 --- Log message: Fix a case where constantexprs could leak into the PPC isel. --- Diffs of the changes: (+4 -1) Index: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp diff -u llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.58 llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.59 --- llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.58 Tue Aug 10 22:30:55 2004 +++ llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp Wed Aug 11 02:34:50 2004 @@ -1260,7 +1260,10 @@ if (Val) { if (Constant *C = dyn_cast(Val)) { Val = ConstantExpr::getCast(C, Type::IntTy); - Ty = Type::IntTy; + if (isa(Val)) // Could not fold + Val = C; + else + Ty = Type::IntTy; // Folded! } // If this is a simple constant, just emit a load directly to avoid the copy From natebegeman at mac.com Wed Aug 11 02:40:15 2004 From: natebegeman at mac.com (Nate Begeman) Date: Wed, 11 Aug 2004 02:40:15 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp PPC32JITInfo.h PPC32TargetMachine.h PPC64JITInfo.h PPC64TargetMachine.h PowerPC.h PowerPCTargetMachine.cpp PowerPCTargetMachine.h PPC32.h PPC32TargetMachine.cpp PPC64.h PPC64TargetMachine.cpp Message-ID: <200408110740.CAA27098@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC32ISelSimple.cpp updated: 1.59 -> 1.60 PPC32JITInfo.h updated: 1.1 -> 1.2 PPC32TargetMachine.h updated: 1.1 -> 1.2 PPC64JITInfo.h updated: 1.1 -> 1.2 PPC64TargetMachine.h updated: 1.1 -> 1.2 PowerPC.h updated: 1.5 -> 1.6 PowerPCTargetMachine.cpp updated: 1.24 -> 1.25 PowerPCTargetMachine.h updated: 1.4 -> 1.5 PPC32.h (r1.1) removed PPC32TargetMachine.cpp (r1.1) removed PPC64.h (r1.1) removed PPC64TargetMachine.cpp (r1.1) removed --- Log message: Clean up 32/64bit and Darwin/AIX split. Next steps: 64 bit ISel, AIX asm printer. --- Diffs of the changes: (+140 -24) Index: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp diff -u llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.59 llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.60 --- llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.59 Wed Aug 11 02:34:50 2004 +++ llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp Wed Aug 11 02:40:04 2004 @@ -11,7 +11,6 @@ #include "PowerPC.h" #include "PowerPCInstrBuilder.h" #include "PowerPCInstrInfo.h" -#include "PPC32.h" #include "PPC32TargetMachine.h" #include "llvm/Constants.h" #include "llvm/DerivedTypes.h" Index: llvm/lib/Target/PowerPC/PPC32JITInfo.h diff -u llvm/lib/Target/PowerPC/PPC32JITInfo.h:1.1 llvm/lib/Target/PowerPC/PPC32JITInfo.h:1.2 --- llvm/lib/Target/PowerPC/PPC32JITInfo.h:1.1 Tue Aug 10 19:09:42 2004 +++ llvm/lib/Target/PowerPC/PPC32JITInfo.h Wed Aug 11 02:40:04 2004 @@ -24,12 +24,6 @@ public: PPC32JITInfo(TargetMachine &tm) : PowerPCJITInfo(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 Index: llvm/lib/Target/PowerPC/PPC32TargetMachine.h diff -u llvm/lib/Target/PowerPC/PPC32TargetMachine.h:1.1 llvm/lib/Target/PowerPC/PPC32TargetMachine.h:1.2 --- llvm/lib/Target/PowerPC/PPC32TargetMachine.h:1.1 Tue Aug 10 19:09:42 2004 +++ llvm/lib/Target/PowerPC/PPC32TargetMachine.h Wed Aug 11 02:40:04 2004 @@ -38,14 +38,7 @@ virtual bool addPassesToEmitMachineCode(FunctionPassManager &PM, MachineCodeEmitter &MCE); - virtual bool addPassesToEmitAssembly(PassManager &PM, std::ostream &Out); - static unsigned getModuleMatchQuality(const Module &M); - - // Two shared sets between the instruction selector and the printer allow for - // correct linkage on Darwin - std::set CalledFunctions; - std::set AddressTaken; }; } // end namespace llvm Index: llvm/lib/Target/PowerPC/PPC64JITInfo.h diff -u llvm/lib/Target/PowerPC/PPC64JITInfo.h:1.1 llvm/lib/Target/PowerPC/PPC64JITInfo.h:1.2 --- llvm/lib/Target/PowerPC/PPC64JITInfo.h:1.1 Tue Aug 10 19:10:41 2004 +++ llvm/lib/Target/PowerPC/PPC64JITInfo.h Wed Aug 11 02:40:04 2004 @@ -23,12 +23,6 @@ public: PPC64JITInfo(TargetMachine &tm) : PowerPCJITInfo(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 Index: llvm/lib/Target/PowerPC/PPC64TargetMachine.h diff -u llvm/lib/Target/PowerPC/PPC64TargetMachine.h:1.1 llvm/lib/Target/PowerPC/PPC64TargetMachine.h:1.2 --- llvm/lib/Target/PowerPC/PPC64TargetMachine.h:1.1 Tue Aug 10 19:10:41 2004 +++ llvm/lib/Target/PowerPC/PPC64TargetMachine.h Wed Aug 11 02:40:04 2004 @@ -31,8 +31,6 @@ virtual bool addPassesToEmitMachineCode(FunctionPassManager &PM, MachineCodeEmitter &MCE); - virtual bool addPassesToEmitAssembly(PassManager &PM, std::ostream &Out); - static unsigned getModuleMatchQuality(const Module &M); }; Index: llvm/lib/Target/PowerPC/PowerPC.h diff -u llvm/lib/Target/PowerPC/PowerPC.h:1.5 llvm/lib/Target/PowerPC/PowerPC.h:1.6 --- llvm/lib/Target/PowerPC/PowerPC.h:1.5 Tue Aug 10 19:11:25 2004 +++ llvm/lib/Target/PowerPC/PowerPC.h Wed Aug 11 02:40:04 2004 @@ -15,12 +15,18 @@ #ifndef TARGET_POWERPC_H #define TARGET_POWERPC_H +#include + namespace llvm { class FunctionPass; +class TargetMachine; FunctionPass *createPowerPCPEI(); FunctionPass *createPPCBranchSelectionPass(); +FunctionPass *createPPC32ISelSimple(TargetMachine &TM); +FunctionPass *createPPC64ISelSimple(TargetMachine &TM); +FunctionPass *createPPC32AsmPrinter(std::ostream &OS,TargetMachine &TM); } // end namespace llvm; Index: llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp diff -u llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.24 llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.25 --- llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.24 Tue Aug 10 19:11:25 2004 +++ llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp Wed Aug 11 02:40:04 2004 @@ -10,8 +10,12 @@ // //===----------------------------------------------------------------------===// -#include "PowerPCTargetMachine.h" #include "PowerPC.h" +#include "PowerPCTargetMachine.h" +#include "PPC32TargetMachine.h" +#include "PPC64TargetMachine.h" +#include "PPC32JITInfo.h" +#include "PPC64JITInfo.h" #include "llvm/Module.h" #include "llvm/PassManager.h" #include "llvm/CodeGen/IntrinsicLowering.h" @@ -20,9 +24,25 @@ #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetMachineRegistry.h" #include "llvm/Transforms/Scalar.h" +#include "Support/CommandLine.h" #include using namespace llvm; +namespace { + cl::opt + AIX("aix", + cl::desc("Generate AIX/xcoff rather than Darwin/macho"), + cl::Hidden); + const std::string PPC32 = "PowerPC/32bit"; + const std::string PPC64 = "PowerPC/64bit"; + + // Register the targets + RegisterTarget + X("ppc32", " PowerPC 32bit (experimental)"); + RegisterTarget + Y("ppc64", " PowerPC 64bit (unimplemented)"); +} + PowerPCTargetMachine::PowerPCTargetMachine(const std::string &name, IntrinsicLowering *IL, const TargetData &TD, @@ -38,8 +58,74 @@ #endif } +/// addPassesToEmitAssembly - Add passes to the specified pass manager +/// to implement a static compiler for this target. +/// +bool PowerPCTargetMachine::addPassesToEmitAssembly(PassManager &PM, + std::ostream &Out) { + bool LP64 = (0 != dynamic_cast(this)); + + // FIXME: Implement efficient support for garbage collection intrinsics. + PM.add(createLowerGCPass()); + + // FIXME: Implement the invoke/unwind instructions! + PM.add(createLowerInvokePass()); + + // FIXME: Implement the switch instruction in the instruction selector! + PM.add(createLowerSwitchPass()); + + PM.add(createLowerConstantExpressionsPass()); + + // Make sure that no unreachable blocks are instruction selected. + PM.add(createUnreachableBlockEliminationPass()); + + if (LP64) + PM.add(createPPC32ISelSimple(*this)); + else + PM.add(createPPC32ISelSimple(*this)); + + if (PrintMachineCode) + PM.add(createMachineFunctionPrinterPass(&std::cerr)); + + PM.add(createRegisterAllocator()); + + if (PrintMachineCode) + PM.add(createMachineFunctionPrinterPass(&std::cerr)); + + // I want a PowerPC specific prolog/epilog code inserter so I can put the + // fills/spills in the right spots. + PM.add(createPowerPCPEI()); + + // Must run branch selection immediately preceding the printer + PM.add(createPPCBranchSelectionPass()); + + if (AIX) + PM.add(createPPC32AsmPrinter(Out, *this)); + else + PM.add(createPPC32AsmPrinter(Out, *this)); + + PM.add(createMachineCodeDeleter()); + return false; +} + void PowerPCJITInfo::addPassesToJITCompile(FunctionPassManager &PM) { - assert(0 && "Cannot execute PowerPCJITInfo::addPassesToJITCompile()"); + // FIXME: Implement efficient support for garbage collection intrinsics. + PM.add(createLowerGCPass()); + + // FIXME: Implement the invoke/unwind instructions! + PM.add(createLowerInvokePass()); + + // FIXME: Implement the switch instruction in the instruction selector! + PM.add(createLowerSwitchPass()); + + PM.add(createLowerConstantExpressionsPass()); + + // Make sure that no unreachable blocks are instruction selected. + PM.add(createUnreachableBlockEliminationPass()); + + PM.add(createPPC32ISelSimple(TM)); + PM.add(createRegisterAllocator()); + PM.add(createPrologEpilogCodeInserter()); } void PowerPCJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { @@ -51,3 +137,42 @@ assert(0 && "Cannot execute PowerPCJITInfo::getJITStubForFunction()"); return 0; } + +/// PowerPCTargetMachine ctor - Create an ILP32 architecture model +/// +PPC32TargetMachine::PPC32TargetMachine(const Module &M, + IntrinsicLowering *IL) + : PowerPCTargetMachine(PPC32, IL, + TargetData(PPC32,false,4,4,4,4,4,4,2,1,4), + TargetFrameInfo(TargetFrameInfo::StackGrowsDown,16,0), + PPC32JITInfo(*this)) {} + +/// PPC64TargetMachine ctor - Create a LP64 architecture model +/// +PPC64TargetMachine::PPC64TargetMachine(const Module &M, IntrinsicLowering *IL) + : PowerPCTargetMachine(PPC64, IL, + TargetData(PPC64,false,8,4,4,4,4,4,2,1,4), + TargetFrameInfo(TargetFrameInfo::StackGrowsDown,16,0), + PPC64JITInfo(*this)) {} + +unsigned PPC32TargetMachine::getModuleMatchQuality(const Module &M) { + if (M.getEndianness() == Module::BigEndian && + M.getPointerSize() == Module::Pointer32) + return 10; // Direct match + else if (M.getEndianness() != Module::AnyEndianness || + M.getPointerSize() != Module::AnyPointerSize) + return 0; // Match for some other target + + return getJITMatchQuality()/2; +} + +unsigned PPC64TargetMachine::getModuleMatchQuality(const Module &M) { + if (M.getEndianness() == Module::BigEndian && + M.getPointerSize() == Module::Pointer64) + return 10; // Direct match + else if (M.getEndianness() != Module::AnyEndianness || + M.getPointerSize() != Module::AnyPointerSize) + return 0; // Match for some other target + + return getJITMatchQuality()/2; +} Index: llvm/lib/Target/PowerPC/PowerPCTargetMachine.h diff -u llvm/lib/Target/PowerPC/PowerPCTargetMachine.h:1.4 llvm/lib/Target/PowerPC/PowerPCTargetMachine.h:1.5 --- llvm/lib/Target/PowerPC/PowerPCTargetMachine.h:1.4 Tue Aug 10 19:11:25 2004 +++ llvm/lib/Target/PowerPC/PowerPCTargetMachine.h Wed Aug 11 02:40:04 2004 @@ -46,6 +46,13 @@ } static unsigned getJITMatchQuality(); + + virtual bool addPassesToEmitAssembly(PassManager &PM, std::ostream &Out); + + // Two shared sets between the instruction selector and the printer allow for + // correct linkage on Darwin + std::set CalledFunctions; + std::set AddressTaken; }; } // end namespace llvm From brukman at cs.uiuc.edu Wed Aug 11 08:36:02 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 08:36:02 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp Message-ID: <200408111336.IAA30496@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCTargetMachine.cpp updated: 1.25 -> 1.26 --- Log message: Hyphenate ##-bit and remove first-person from comments. --- Diffs of the changes: (+4 -4) Index: llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp diff -u llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.25 llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.26 --- llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.25 Wed Aug 11 02:40:04 2004 +++ llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp Wed Aug 11 08:35:44 2004 @@ -38,9 +38,9 @@ // Register the targets RegisterTarget - X("ppc32", " PowerPC 32bit (experimental)"); + X("ppc32", " PowerPC 32-bit (experimental)"); RegisterTarget - Y("ppc64", " PowerPC 64bit (unimplemented)"); + Y("ppc64", " PowerPC 64-bit (unimplemented)"); } PowerPCTargetMachine::PowerPCTargetMachine(const std::string &name, @@ -92,8 +92,8 @@ if (PrintMachineCode) PM.add(createMachineFunctionPrinterPass(&std::cerr)); - // I want a PowerPC specific prolog/epilog code inserter so I can put the - // fills/spills in the right spots. + // PowerPC-specific prolog/epilog code inserter to put the fills/spills in the + // right spots. PM.add(createPowerPCPEI()); // Must run branch selection immediately preceding the printer From brukman at cs.uiuc.edu Wed Aug 11 09:16:44 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 09:16:44 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/CodeGen/Generic/Makefile branch.c call-ret0.ll call-ret42.ll call-void.ll call2-ret0.ll cast-fp.ll global-ret0.ll hello.ll print-add.ll print-arith-fp.ll print-arith-int.ll print-int.ll print-mul-exp.ll print-mul.ll print-shift.ll print-vals.c ret0.ll ret42.ll struct.c Message-ID: <200408111416.JAA31009@zion.cs.uiuc.edu> Changes in directory llvm/test/Regression/CodeGen/Generic: Makefile added (r1.1) branch.c added (r1.1) call-ret0.ll added (r1.1) call-ret42.ll added (r1.1) call-void.ll added (r1.1) call2-ret0.ll added (r1.1) cast-fp.ll added (r1.1) global-ret0.ll added (r1.1) hello.ll added (r1.1) print-add.ll added (r1.1) print-arith-fp.ll added (r1.1) print-arith-int.ll added (r1.1) print-int.ll added (r1.1) print-mul-exp.ll added (r1.1) print-mul.ll added (r1.1) print-shift.ll added (r1.1) print-vals.c added (r1.1) ret0.ll added (r1.1) ret42.ll added (r1.1) struct.c added (r1.1) --- Log message: Simple hand-coded tests to aid in early development of backends, along with a Makefile to run ad-hoc tests easily. --- Diffs of the changes: (+511 -0) Index: llvm/test/Regression/CodeGen/Generic/Makefile diff -c /dev/null llvm/test/Regression/CodeGen/Generic/Makefile:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/Makefile Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,23 ---- + # Makefile for running ad-hoc custom LLVM tests + # + %.bc: %.ll + llvm-as -f $< + + %.llc.s: %.bc + llc -f $< -o $@ + + %.gcc.s: %.c + gcc -O0 -S $< -o $@ + + %.nat: %.s + gcc -O0 -lm $< -o $@ + + %.cbe.out: %.cbe.nat + ./$< > $@ + + %.out: %.nat + ./$< > $@ + + %.clean: + rm -f $(patsubst %.clean,%.bc,$@) $(patsubst %.clean,%.*.s,$@) \ + $(patsubst %.clean,%.*.nat,$@) $(patsubst %.clean,%.*.out,$@) Index: llvm/test/Regression/CodeGen/Generic/branch.c diff -c /dev/null llvm/test/Regression/CodeGen/Generic/branch.c:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/branch.c Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,15 ---- + #include + int a = 1, b = 2; + + int main() { + int i,j; + for (i=15; i>=0; --i) { + if (a < i) printf("%d < %d\n", a, i); + else printf("%d >= %d\n", a, i); + for (j=2; j <= 25; j++) { + printf("%d, ", j); + } + printf("\n"); + } + return 0; + } Index: llvm/test/Regression/CodeGen/Generic/call-ret0.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/call-ret0.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/call-ret0.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,8 ---- + int %foo(int %x) { + ret int %x + } + + int %main() { + %r = call int %foo(int 0) + ret int %r + } Index: llvm/test/Regression/CodeGen/Generic/call-ret42.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/call-ret42.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/call-ret42.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,8 ---- + int %foo(int %x) { + ret int 42 + } + + int %main() { + %r = call int %foo(int 15) + ret int %r + } Index: llvm/test/Regression/CodeGen/Generic/call-void.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/call-void.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/call-void.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,8 ---- + void %foo() { + ret void + } + + int %main() { + call void ()* %foo() + ret int 0 + } Index: llvm/test/Regression/CodeGen/Generic/call2-ret0.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/call2-ret0.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/call2-ret0.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,13 ---- + int %bar(int %x) { + ret int 0 + } + + int %foo(int %x) { + %q = call int %bar(int 1) + ret int %q + } + + int %main() { + %r = call int %foo(int 2) + ret int %r + } Index: llvm/test/Regression/CodeGen/Generic/cast-fp.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/cast-fp.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/cast-fp.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,47 ---- + %a_fstr = internal constant [8 x sbyte] c"a = %f\0A\00" + %a_lstr = internal constant [10 x sbyte] c"a = %lld\0A\00" + %a_dstr = internal constant [8 x sbyte] c"a = %d\0A\00" + + %b_dstr = internal constant [8 x sbyte] c"b = %d\0A\00" + %b_fstr = internal constant [8 x sbyte] c"b = %f\0A\00" + + declare int %printf(sbyte*, ...) + %A = global double 2.0 + %B = global int 2 + + int %main() { + ;; A + %a = load double* %A + %a_fs = getelementptr [8 x sbyte]* %a_fstr, long 0, long 0 + call int (sbyte*, ...)* %printf(sbyte* %a_fs, double %a) + + ;; cast double to long + %a_d2l = cast double %a to long + %a_ls = getelementptr [10 x sbyte]* %a_lstr, long 0, long 0 + call int (sbyte*, ...)* %printf(sbyte* %a_ls, long %a_d2l) + + ;; cast double to int + %a_d2i = cast double %a to int + %a_ds = getelementptr [8 x sbyte]* %a_dstr, long 0, long 0 + call int (sbyte*, ...)* %printf(sbyte* %a_ds, int %a_d2i) + + ;; cast double to sbyte + %a_d2sb = cast double %a to sbyte + call int (sbyte*, ...)* %printf(sbyte* %a_ds, sbyte %a_d2sb) + + ;; cast int to sbyte + %a_d2i2sb = cast int %a_d2i to sbyte + call int (sbyte*, ...)* %printf(sbyte* %a_ds, sbyte %a_d2i2sb) + + ;; B + %b = load int* %B + %b_ds = getelementptr [8 x sbyte]* %b_dstr, long 0, long 0 + call int (sbyte*, ...)* %printf(sbyte* %b_ds, int %b) + + ;; cast int to double + %b_i2d = cast int %b to double + %b_fs = getelementptr [8 x sbyte]* %b_fstr, long 0, long 0 + call int (sbyte*, ...)* %printf(sbyte* %b_fs, double %b_i2d) + + ret int 0 + } Index: llvm/test/Regression/CodeGen/Generic/global-ret0.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/global-ret0.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/global-ret0.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,6 ---- + %g = global int 0 + + int %main() { + %h = load int* %g + ret int %h + } Index: llvm/test/Regression/CodeGen/Generic/hello.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/hello.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/hello.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,9 ---- + %.str_1 = internal constant [7 x sbyte] c"hello\0A\00" + + declare int %printf(sbyte*, ...) + + int %main() { + %s = getelementptr [7 x sbyte]* %.str_1, long 0, long 0 + call int (sbyte*, ...)* %printf(sbyte* %s) + ret int 0 + } Index: llvm/test/Regression/CodeGen/Generic/print-add.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/print-add.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/print-add.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,16 ---- + %.str_1 = internal constant [4 x sbyte] c"%d\0A\00" + + declare int %printf(sbyte*, ...) + + int %main() { + %f = getelementptr [4 x sbyte]* %.str_1, long 0, long 0 + %d = add int 1, 0 + call int (sbyte*, ...)* %printf(sbyte* %f, int %d) + %e = add int 38, 2 + call int (sbyte*, ...)* %printf(sbyte* %f, int %e) + %g = add int %d, %d + %h = add int %e, %g + call int (sbyte*, ...)* %printf(sbyte* %f, int %h) + ret int 0 + } + Index: llvm/test/Regression/CodeGen/Generic/print-arith-fp.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/print-arith-fp.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/print-arith-fp.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,74 ---- + %a_str = internal constant [8 x sbyte] c"a = %f\0A\00" + %b_str = internal constant [8 x sbyte] c"b = %f\0A\00" + ;; binary ops: arith + %add_str = internal constant [12 x sbyte] c"a + b = %f\0A\00" + %sub_str = internal constant [12 x sbyte] c"a - b = %f\0A\00" + %mul_str = internal constant [12 x sbyte] c"a * b = %f\0A\00" + %div_str = internal constant [12 x sbyte] c"b / a = %f\0A\00" + %rem_str = internal constant [13 x sbyte] c"b %% a = %f\0A\00" + ;; binary ops: setcc + %lt_str = internal constant [12 x sbyte] c"a < b = %d\0A\00" + %le_str = internal constant [13 x sbyte] c"a <= b = %d\0A\00" + %gt_str = internal constant [12 x sbyte] c"a > b = %d\0A\00" + %ge_str = internal constant [13 x sbyte] c"a >= b = %d\0A\00" + %eq_str = internal constant [13 x sbyte] c"a == b = %d\0A\00" + %ne_str = internal constant [13 x sbyte] c"a != b = %d\0A\00" + + declare int %printf(sbyte*, ...) + %A = global double 2.0 + %B = global double 5.0 + + int %main() { + ;; main vars + %a = load double* %A + %b = load double* %B + + %a_s = getelementptr [8 x sbyte]* %a_str, long 0, long 0 + %b_s = getelementptr [8 x sbyte]* %b_str, long 0, long 0 + + call int (sbyte*, ...)* %printf(sbyte* %a_s, double %a) + call int (sbyte*, ...)* %printf(sbyte* %b_s, double %b) + + ;; arithmetic + %add_r = add double %a, %b + %sub_r = sub double %a, %b + %mul_r = mul double %a, %b + %div_r = div double %b, %a + %rem_r = rem double %b, %a + + %add_s = getelementptr [12 x sbyte]* %add_str, long 0, long 0 + %sub_s = getelementptr [12 x sbyte]* %sub_str, long 0, long 0 + %mul_s = getelementptr [12 x sbyte]* %mul_str, long 0, long 0 + %div_s = getelementptr [12 x sbyte]* %div_str, long 0, long 0 + %rem_s = getelementptr [13 x sbyte]* %rem_str, long 0, long 0 + + call int (sbyte*, ...)* %printf(sbyte* %add_s, double %add_r) + call int (sbyte*, ...)* %printf(sbyte* %sub_s, double %sub_r) + call int (sbyte*, ...)* %printf(sbyte* %mul_s, double %mul_r) + call int (sbyte*, ...)* %printf(sbyte* %div_s, double %div_r) + call int (sbyte*, ...)* %printf(sbyte* %rem_s, double %rem_r) + + ;; setcc + %lt_r = setlt double %a, %b + %le_r = setle double %a, %b + %gt_r = setgt double %a, %b + %ge_r = setge double %a, %b + %eq_r = seteq double %a, %b + %ne_r = setne double %a, %b + + %lt_s = getelementptr [12 x sbyte]* %lt_str, long 0, long 0 + %le_s = getelementptr [13 x sbyte]* %le_str, long 0, long 0 + %gt_s = getelementptr [12 x sbyte]* %gt_str, long 0, long 0 + %ge_s = getelementptr [13 x sbyte]* %ge_str, long 0, long 0 + %eq_s = getelementptr [13 x sbyte]* %eq_str, long 0, long 0 + %ne_s = getelementptr [13 x sbyte]* %ne_str, long 0, long 0 + + call int (sbyte*, ...)* %printf(sbyte* %lt_s, bool %lt_r) + call int (sbyte*, ...)* %printf(sbyte* %le_s, bool %le_r) + call int (sbyte*, ...)* %printf(sbyte* %gt_s, bool %gt_r) + call int (sbyte*, ...)* %printf(sbyte* %ge_s, bool %ge_r) + call int (sbyte*, ...)* %printf(sbyte* %eq_s, bool %eq_r) + call int (sbyte*, ...)* %printf(sbyte* %ne_s, bool %ne_r) + + ret int 0 + } Index: llvm/test/Regression/CodeGen/Generic/print-arith-int.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/print-arith-int.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/print-arith-int.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,100 ---- + %a_str = internal constant [8 x sbyte] c"a = %d\0A\00" + %b_str = internal constant [8 x sbyte] c"b = %d\0A\00" + ;; binary ops: arith + %add_str = internal constant [12 x sbyte] c"a + b = %d\0A\00" + %sub_str = internal constant [12 x sbyte] c"a - b = %d\0A\00" + %mul_str = internal constant [12 x sbyte] c"a * b = %d\0A\00" + %div_str = internal constant [12 x sbyte] c"b / a = %d\0A\00" + %rem_str = internal constant [13 x sbyte] c"b \% a = %d\0A\00" + ;; binary ops: setcc + %lt_str = internal constant [12 x sbyte] c"a < b = %d\0A\00" + %le_str = internal constant [13 x sbyte] c"a <= b = %d\0A\00" + %gt_str = internal constant [12 x sbyte] c"a > b = %d\0A\00" + %ge_str = internal constant [13 x sbyte] c"a >= b = %d\0A\00" + %eq_str = internal constant [13 x sbyte] c"a == b = %d\0A\00" + %ne_str = internal constant [13 x sbyte] c"a != b = %d\0A\00" + ;; logical + %and_str = internal constant [12 x sbyte] c"a & b = %d\0A\00" + %or_str = internal constant [12 x sbyte] c"a | b = %d\0A\00" + %xor_str = internal constant [12 x sbyte] c"a ^ b = %d\0A\00" + %shl_str = internal constant [13 x sbyte] c"b << a = %d\0A\00" + %shr_str = internal constant [13 x sbyte] c"b >> a = %d\0A\00" + + declare int %printf(sbyte*, ...) + %A = global int 2 + %B = global int 5 + + int %main() { + ;; main vars + %a = load int* %A + %b = load int* %B + + %a_s = getelementptr [8 x sbyte]* %a_str, long 0, long 0 + %b_s = getelementptr [8 x sbyte]* %b_str, long 0, long 0 + + call int (sbyte*, ...)* %printf(sbyte* %a_s, int %a) + call int (sbyte*, ...)* %printf(sbyte* %b_s, int %b) + + ;; arithmetic + %add_r = add int %a, %b + %sub_r = sub int %a, %b + %mul_r = mul int %a, %b + %div_r = div int %b, %a + %rem_r = rem int %b, %a + + %add_s = getelementptr [12 x sbyte]* %add_str, long 0, long 0 + %sub_s = getelementptr [12 x sbyte]* %sub_str, long 0, long 0 + %mul_s = getelementptr [12 x sbyte]* %mul_str, long 0, long 0 + %div_s = getelementptr [12 x sbyte]* %div_str, long 0, long 0 + %rem_s = getelementptr [13 x sbyte]* %rem_str, long 0, long 0 + + call int (sbyte*, ...)* %printf(sbyte* %add_s, int %add_r) + call int (sbyte*, ...)* %printf(sbyte* %sub_s, int %sub_r) + call int (sbyte*, ...)* %printf(sbyte* %mul_s, int %mul_r) + call int (sbyte*, ...)* %printf(sbyte* %div_s, int %div_r) + call int (sbyte*, ...)* %printf(sbyte* %rem_s, int %rem_r) + + ;; setcc + %lt_r = setlt int %a, %b + %le_r = setle int %a, %b + %gt_r = setgt int %a, %b + %ge_r = setge int %a, %b + %eq_r = seteq int %a, %b + %ne_r = setne int %a, %b + + %lt_s = getelementptr [12 x sbyte]* %lt_str, long 0, long 0 + %le_s = getelementptr [13 x sbyte]* %le_str, long 0, long 0 + %gt_s = getelementptr [12 x sbyte]* %gt_str, long 0, long 0 + %ge_s = getelementptr [13 x sbyte]* %ge_str, long 0, long 0 + %eq_s = getelementptr [13 x sbyte]* %eq_str, long 0, long 0 + %ne_s = getelementptr [13 x sbyte]* %ne_str, long 0, long 0 + + call int (sbyte*, ...)* %printf(sbyte* %lt_s, bool %lt_r) + call int (sbyte*, ...)* %printf(sbyte* %le_s, bool %le_r) + call int (sbyte*, ...)* %printf(sbyte* %gt_s, bool %gt_r) + call int (sbyte*, ...)* %printf(sbyte* %ge_s, bool %ge_r) + call int (sbyte*, ...)* %printf(sbyte* %eq_s, bool %eq_r) + call int (sbyte*, ...)* %printf(sbyte* %ne_s, bool %ne_r) + + ;; logical + %and_r = and int %a, %b + %or_r = or int %a, %b + %xor_r = xor int %a, %b + %u = cast int %a to ubyte + %shl_r = shl int %b, ubyte %u + %shr_r = shr int %b, ubyte %u + + %and_s = getelementptr [12 x sbyte]* %and_str, long 0, long 0 + %or_s = getelementptr [12 x sbyte]* %or_str, long 0, long 0 + %xor_s = getelementptr [12 x sbyte]* %xor_str, long 0, long 0 + %shl_s = getelementptr [13 x sbyte]* %shl_str, long 0, long 0 + %shr_s = getelementptr [13 x sbyte]* %shr_str, long 0, long 0 + + call int (sbyte*, ...)* %printf(sbyte* %and_s, int %and_r) + call int (sbyte*, ...)* %printf(sbyte* %or_s, int %or_r) + call int (sbyte*, ...)* %printf(sbyte* %xor_s, int %xor_r) + call int (sbyte*, ...)* %printf(sbyte* %shl_s, int %shl_r) + call int (sbyte*, ...)* %printf(sbyte* %shr_s, int %shr_r) + + ret int 0 + } Index: llvm/test/Regression/CodeGen/Generic/print-int.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/print-int.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/print-int.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,11 ---- + %.str_1 = internal constant [4 x sbyte] c"%d\0A\00" + + declare int %printf(sbyte*, ...) + + int %main() { + %f = getelementptr [4 x sbyte]* %.str_1, long 0, long 0 + %d = add int 0, 0 + %tmp.0 = call int (sbyte*, ...)* %printf(sbyte* %f, int %d) + ret int 0 + } + Index: llvm/test/Regression/CodeGen/Generic/print-mul-exp.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/print-mul-exp.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/print-mul-exp.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,55 ---- + %a_str = internal constant [8 x sbyte] c"a = %d\0A\00" + %a_mul_str = internal constant [13 x sbyte] c"a * %d = %d\0A\00" + %A = global int 2 + declare int %printf(sbyte*, ...) + + int %main() { + %a = load int* %A + %a_s = getelementptr [8 x sbyte]* %a_str, long 0, long 0 + %a_mul_s = getelementptr [13 x sbyte]* %a_mul_str, long 0, long 0 + call int (sbyte*, ...)* %printf(sbyte* %a_s, int %a) + + %r_0 = mul int %a, 0 + %r_1 = mul int %a, 1 + %r_2 = mul int %a, 2 + %r_3 = mul int %a, 3 + %r_4 = mul int %a, 4 + %r_5 = mul int %a, 5 + %r_6 = mul int %a, 6 + %r_7 = mul int %a, 7 + %r_8 = mul int %a, 8 + %r_9 = mul int %a, 9 + %r_10 = mul int %a, 10 + %r_11 = mul int %a, 11 + %r_12 = mul int %a, 12 + %r_13 = mul int %a, 13 + %r_14 = mul int %a, 14 + %r_15 = mul int %a, 15 + %r_16 = mul int %a, 16 + %r_17 = mul int %a, 17 + %r_18 = mul int %a, 18 + %r_19 = mul int %a, 19 + + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 0, int %r_0) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 1, int %r_1) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 2, int %r_2) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 3, int %r_3) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 4, int %r_4) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 5, int %r_5) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 6, int %r_6) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 7, int %r_7) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 8, int %r_8) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 9, int %r_9) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 10, int %r_10) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 11, int %r_11) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 12, int %r_12) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 13, int %r_13) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 14, int %r_14) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 15, int %r_15) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 16, int %r_16) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 17, int %r_17) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 18, int %r_18) + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int 19, int %r_19) + + ret int 0 + } Index: llvm/test/Regression/CodeGen/Generic/print-mul.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/print-mul.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/print-mul.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,33 ---- + %a_str = internal constant [8 x sbyte] c"a = %d\0A\00" + %b_str = internal constant [8 x sbyte] c"b = %d\0A\00" + + ;; mul + %a_mul_str = internal constant [13 x sbyte] c"a * %d = %d\0A\00" + + declare int %printf(sbyte*, ...) + %A = global int 2 + %B = global int 5 + + int %main() { + entry: + %a = load int* %A + %b = load int* %B + %a_s = getelementptr [8 x sbyte]* %a_str, long 0, long 0 + %b_s = getelementptr [8 x sbyte]* %b_str, long 0, long 0 + %a_mul_s = getelementptr [13 x sbyte]* %a_mul_str, long 0, long 0 + call int (sbyte*, ...)* %printf(sbyte* %a_s, int %a) + call int (sbyte*, ...)* %printf(sbyte* %b_s, int %b) + br label %shl_test + + shl_test: + ;; test mul by 0-255 + %s = phi int [ 0, %entry ], [ %s_inc, %shl_test ] + %result = mul int %a, %s + call int (sbyte*, ...)* %printf(sbyte* %a_mul_s, int %s, int %result) + %s_inc = add int %s, 1 + %done = seteq int %s, 256 + br bool %done, label %fini, label %shl_test + + fini: + ret int 0 + } Index: llvm/test/Regression/CodeGen/Generic/print-shift.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/print-shift.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/print-shift.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,33 ---- + %a_str = internal constant [8 x sbyte] c"a = %d\0A\00" + %b_str = internal constant [8 x sbyte] c"b = %d\0A\00" + + ;; shl + %a_shl_str = internal constant [14 x sbyte] c"a << %d = %d\0A\00" + + declare int %printf(sbyte*, ...) + %A = global int 2 + %B = global int 5 + + int %main() { + entry: + %a = load int* %A + %b = load int* %B + %a_s = getelementptr [8 x sbyte]* %a_str, long 0, long 0 + %b_s = getelementptr [8 x sbyte]* %b_str, long 0, long 0 + %a_shl_s = getelementptr [14 x sbyte]* %a_shl_str, long 0, long 0 + call int (sbyte*, ...)* %printf(sbyte* %a_s, int %a) + call int (sbyte*, ...)* %printf(sbyte* %b_s, int %b) + br label %shl_test + + shl_test: + ;; test left shifts 0-31 + %s = phi ubyte [ 0, %entry ], [ %s_inc, %shl_test ] + %result = shl int %a, ubyte %s + call int (sbyte*, ...)* %printf(sbyte* %a_shl_s, ubyte %s, int %result) + %s_inc = add ubyte %s, 1 + %done = seteq ubyte %s, 32 + br bool %done, label %fini, label %shl_test + + fini: + ret int 0 + } Index: llvm/test/Regression/CodeGen/Generic/print-vals.c diff -c /dev/null llvm/test/Regression/CodeGen/Generic/print-vals.c:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/print-vals.c Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,7 ---- + void printf(char*, ...); + + int main() { + printf("%f, %d, %f, %d, %f\n", //, %d, %f, %d, %f, %d\n", + 1.0, 2, 3.0, 4, 5.0 /*, 6, 7.0, 8, 9.0, 10*/); + return 0; + } Index: llvm/test/Regression/CodeGen/Generic/ret0.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/ret0.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/ret0.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,3 ---- + int %main() { + ret int 0 + } Index: llvm/test/Regression/CodeGen/Generic/ret42.ll diff -c /dev/null llvm/test/Regression/CodeGen/Generic/ret42.ll:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/ret42.ll Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,3 ---- + int %main() { + ret int 42 + } Index: llvm/test/Regression/CodeGen/Generic/struct.c diff -c /dev/null llvm/test/Regression/CodeGen/Generic/struct.c:1.1 *** /dev/null Wed Aug 11 09:16:44 2004 --- llvm/test/Regression/CodeGen/Generic/struct.c Wed Aug 11 09:16:34 2004 *************** *** 0 **** --- 1,39 ---- + void printf(char*, ...); + + typedef struct params_ { + int i1; + float f1; + double d1; + short s1; + double d2; + char c1; + unsigned short s2; + float f2; + int i2; + } params; + + void print_param(params p) { + printf("%d, %f, %f, %d, %f, %c, %d, %f, %d\n", + p.i1, p.f1, p.d1, p.s1, p.d2, p.c1, p.s2, p.f2, p.i2); + } + + void print_param_addr(params *p) { + printf("%d, %f, %f, %d, %f, %c, %d, %f, %d\n", + p->i1, p->f1, p->d1, p->s1, p->d2, p->c1, p->s2, p->f2, p->i2); + } + + int main() { + params p; + p.i1 = 1; + p.f1 = 2.0; + p.d1 = 3.0; + p.s1 = 4; + p.d2 = 5.0; + p.c1 = '6'; + p.s2 = 7; + p.f2 = 8.0; + p.i2 = 9; + print_param(p); + print_param_addr(&p); + return 0; + } From brukman at cs.uiuc.edu Wed Aug 11 10:54:47 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 10:54:47 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td PowerPCInstrInfo.td Message-ID: <200408111554.KAA08047@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCInstrFormats.td updated: 1.9 -> 1.10 PowerPCInstrInfo.td updated: 1.16 -> 1.17 --- Log message: Add doubleword load/store (64-bit only). --- Diffs of the changes: (+29 -5) Index: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.9 llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.10 --- llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.9 Tue Aug 10 17:47:03 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Wed Aug 11 10:54:36 2004 @@ -222,13 +222,35 @@ let Arg0Type = Fpr.Value; } +// 1.7.5 DS-Form +class DSForm_1 opcode, bits<2> xo, bit ppc64, bit vmx> + : I { + field bits<5> RST; + field bits<14> DS; + field bits<5> RA; + + let ArgCount = 3; + let Arg0Type = Gpr.Value; + let Arg1Type = Disimm14.Value; + let Arg2Type = Gpr.Value; + let Arg3Type = 0; + let Arg4Type = 0; + + let Inst{6-10} = RST; + let Inst{11-15} = RA; + let Inst{16-29} = DS; + let Inst{30-31} = xo; +} + +class DSForm_2 opcode, bits<2> xo, bit ppc64, bit vmx> + : DSForm_1; + // 1.7.6 X-Form class XForm_base_r3xo opcode, bits<10> xo, bit rc, bit ppc64, bit vmx> : I { - let ArgCount = 3; - field bits<5> ST; - field bits<5> A; - field bits<5> B; + field bits<5> RST; + field bits<5> A; + field bits<5> B; let ArgCount = 3; let Arg0Type = Gpr.Value; @@ -237,7 +259,7 @@ let Arg3Type = 0; let Arg4Type = 0; - let Inst{6-10} = ST; + let Inst{6-10} = RST; let Inst{11-15} = A; let Inst{16-20} = B; let Inst{21-30} = xo; Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.16 llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.17 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.16 Tue Aug 10 15:42:36 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.td Wed Aug 11 10:54:36 2004 @@ -105,6 +105,7 @@ def LHAX : XForm_1<"lhax", 31, 343, 0, 0>; def LWZ : DForm_1<"lwz", 32, 0, 0>; def LWZX : XForm_1<"lwzx", 31, 23, 0, 0>; +def LD : DSForm_2<"ld", 58, 0, 1, 0>; def LMW : DForm_1<"lmw", 46, 0, 0>; def STMW : DForm_3<"stmw", 47, 0, 0>; def LFS : DForm_8<"lfs", 48, 0, 0>; @@ -143,6 +144,7 @@ def STWU : DForm_3<"stwu", 37, 0, 0>; def STWX : XForm_8<"stwx", 31, 151, 0, 0>; def STWUX : XForm_8<"stwux", 31, 183, 0, 0>; +def STD : DSForm_2<"std", 62, 0, 1, 0>; def STFS : DForm_9<"stfs", 52, 0, 0>; def STFSX : XForm_28<"stfsx", 31, 663, 0, 0>; def STFD : DForm_9<"stfd", 54, 0, 0>; From criswell at cs.uiuc.edu Wed Aug 11 14:48:22 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Wed, 11 Aug 2004 14:48:22 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/docs/GettingStarted.html Message-ID: <200408111948.OAA03389@zion.cs.uiuc.edu> Changes in directory llvm/docs: GettingStarted.html updated: 1.64.2.1 -> 1.64.2.2 --- Log message: Updated code sizes for LLVM. --- Diffs of the changes: (+15 -15) Index: llvm/docs/GettingStarted.html diff -u llvm/docs/GettingStarted.html:1.64.2.1 llvm/docs/GettingStarted.html:1.64.2.2 --- llvm/docs/GettingStarted.html:1.64.2.1 Fri Aug 6 16:26:30 2004 +++ llvm/docs/GettingStarted.html Wed Aug 11 14:48:12 2004 @@ -188,31 +188,31 @@
    • Linux on x86 (Pentium and above)
        -
      • Approximately 1.02 GB of Free Disk Space +
      • Approximately 2.6 GB of Free Disk Space
          -
        • Source code: 45 MB
        • -
        • Object code: 956 MB
        • -
        • GCC front end: 40 MB
        • +
        • Source code: 57 MB
        • +
        • Object code: 2.5 GB
        • +
        • GCC front end: 30 MB
    • Solaris on SparcV9 (Ultrasparc)
        -
      • Approximately 1.75 GB of Free Disk Space +
      • Approximately 2.6 GB of Free Disk Space
          -
        • Source code: 45 MB
        • -
        • Object code: 1705 MB
        • -
        • GCC front end: 50 MB
        • +
        • Source code: 57 MB
        • +
        • Object code: 2.5 GB
        • +
        • GCC front end: 46 MB
    • FreeBSD on x86 (Pentium and above)
        -
      • Approximately 935 MB of Free Disk Space +
      • Approximately 1 GB of Free Disk Space
          -
        • Source code: 45 MB
        • +
        • Source code: 57 MB
        • Object code: 850 MB
        • GCC front end: 40 MB
      • @@ -222,11 +222,11 @@
      • MacOS X on PowerPC
        • Experimental support for static native code generation -
        • Approximately 1.25 GB of Free Disk Space +
        • Approximately 1.6 GB of Free Disk Space
            -
          • Source code: 45 MB
          • -
          • Object code: 1160 MB
          • -
          • GCC front end: 40 MB
          • +
          • Source code: 57 MB
          • +
          • Object code: 1.5 GB
          • +
          • GCC front end: 36 MB
        @@ -1267,7 +1267,7 @@ Chris Lattner
        The LLVM Compiler Infrastructure
        - Last modified: $Date: 2004/08/06 21:26:30 $ + Last modified: $Date: 2004/08/11 19:48:12 $ From brukman at cs.uiuc.edu Wed Aug 11 15:56:25 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 15:56:25 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td PowerPCInstrInfo.td Message-ID: <200408112056.PAA03918@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCInstrFormats.td updated: 1.10 -> 1.11 PowerPCInstrInfo.td updated: 1.17 -> 1.18 --- Log message: Add support for 64-bit CMPDI, CMPLDI, and CMPLD opcodes --- Diffs of the changes: (+6 -3) Index: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.10 llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.11 --- llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.10 Wed Aug 11 10:54:36 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Wed Aug 11 15:56:14 2004 @@ -184,7 +184,7 @@ class DForm_5_ext opcode, bit ppc64, bit vmx> : DForm_5 { - let L = 0; + let L = ppc64; let ArgCount = 3; let Arg0Type = Imm3.Value; let Arg1Type = Gpr.Value; @@ -199,7 +199,7 @@ class DForm_6_ext opcode, bit ppc64, bit vmx> : DForm_6 { - let L = 0; + let L = ppc64; let ArgCount = 3; let Arg0Type = Imm3.Value; let Arg1Type = Gpr.Value; @@ -324,7 +324,7 @@ class XForm_16_ext opcode, bits<10> xo, bit ppc64, bit vmx> : XForm_16 { - let L = 0; + let L = ppc64; } class XForm_17 opcode, bits<10> xo, bit ppc64, bit vmx> Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.17 llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.18 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.17 Wed Aug 11 10:54:36 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.td Wed Aug 11 15:56:14 2004 @@ -69,11 +69,14 @@ def CMPI : DForm_5<"cmpi", 11, 0, 0>; def CMPWI : DForm_5_ext<"cmpwi", 11, 0, 0>; +def CMPDI : DForm_5_ext<"cmpwi", 11, 1, 0>; def CMPW : XForm_16 <"cmpw", 31, 0, 0, 0>; def CMPLI : DForm_6<"cmpli", 10, 0, 0>; def CMPLWI : DForm_6_ext<"cmplwi", 10, 0, 0>; +def CMPLDI : DForm_6_ext<"cmplwi", 10, 1, 0>; def CMPL : XForm_16<"cmpl", 31, 32, 0, 0>; def CMPLW : XForm_16_ext<"cmplw", 31, 32, 0, 0>; +def CMPLD : XForm_16_ext<"cmplw", 31, 32, 1, 0>; def CRAND : XLForm_1<"crand", 19, 257, 0, 0>; def CRANDC : XLForm_1<"crandc", 19, 129, 0, 0>; def CRNOR : XLForm_1<"crnor", 19, 33, 0, 0>; From brukman at cs.uiuc.edu Wed Aug 11 18:33:44 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 18:33:44 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCInstrInfo.td Message-ID: <200408112333.SAA05047@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCInstrInfo.td updated: 1.18 -> 1.19 --- Log message: Fix names of 64-bit CMP*D* opcodes, add LWA and STD* opcodes --- Diffs of the changes: (+10 -4) Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.18 llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.19 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.18 Wed Aug 11 15:56:14 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.td Wed Aug 11 18:33:34 2004 @@ -69,14 +69,16 @@ def CMPI : DForm_5<"cmpi", 11, 0, 0>; def CMPWI : DForm_5_ext<"cmpwi", 11, 0, 0>; -def CMPDI : DForm_5_ext<"cmpwi", 11, 1, 0>; -def CMPW : XForm_16 <"cmpw", 31, 0, 0, 0>; +def CMPDI : DForm_5_ext<"cmpdi", 11, 1, 0>; +def CMP : XForm_16<"cmp", 31, 0, 0, 0>; +def CMPW : XForm_16_ext<"cmpw", 31, 0, 0, 0>; +def CMPD : XForm_16_ext<"cmpd", 31, 0, 1, 0>; def CMPLI : DForm_6<"cmpli", 10, 0, 0>; def CMPLWI : DForm_6_ext<"cmplwi", 10, 0, 0>; -def CMPLDI : DForm_6_ext<"cmplwi", 10, 1, 0>; +def CMPLDI : DForm_6_ext<"cmpldi", 10, 1, 0>; def CMPL : XForm_16<"cmpl", 31, 32, 0, 0>; def CMPLW : XForm_16_ext<"cmplw", 31, 32, 0, 0>; -def CMPLD : XForm_16_ext<"cmplw", 31, 32, 1, 0>; +def CMPLD : XForm_16_ext<"cmpld", 31, 32, 1, 0>; def CRAND : XLForm_1<"crand", 19, 257, 0, 0>; def CRANDC : XLForm_1<"crandc", 19, 129, 0, 0>; def CRNOR : XLForm_1<"crnor", 19, 33, 0, 0>; @@ -108,6 +110,7 @@ def LHAX : XForm_1<"lhax", 31, 343, 0, 0>; def LWZ : DForm_1<"lwz", 32, 0, 0>; def LWZX : XForm_1<"lwzx", 31, 23, 0, 0>; +def LWA : DSForm_1<"lwa", 58, 2, 1, 0>; def LD : DSForm_2<"ld", 58, 0, 1, 0>; def LMW : DForm_1<"lmw", 46, 0, 0>; def STMW : DForm_3<"stmw", 47, 0, 0>; @@ -148,6 +151,9 @@ def STWX : XForm_8<"stwx", 31, 151, 0, 0>; def STWUX : XForm_8<"stwux", 31, 183, 0, 0>; def STD : DSForm_2<"std", 62, 0, 1, 0>; +def STDU : DSForm_2<"stdu", 62, 1, 1, 0>; +def STDX : XForm_8<"stdx", 31, 149, 1, 0>; +def STDUX : XForm_8<"stdux", 31, 181, 1, 0>; def STFS : DForm_9<"stfs", 52, 0, 0>; def STFSX : XForm_28<"stfsx", 31, 663, 0, 0>; def STFD : DForm_9<"stfd", 54, 0, 0>; From brukman at cs.uiuc.edu Wed Aug 11 18:42:26 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 18:42:26 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp PPC64AsmPrinter.cpp PowerPC.h Message-ID: <200408112342.SAA05387@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC64ISelSimple.cpp added (r1.1) PPC64AsmPrinter.cpp added (r1.1) PowerPC.h updated: 1.6 -> 1.7 --- Log message: 64-bit instruction selector and AIX-specific 64-bit asm printer --- Diffs of the changes: (+3887 -1) Index: llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp diff -c /dev/null llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp:1.1 *** /dev/null Wed Aug 11 18:42:25 2004 --- llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp Wed Aug 11 18:42:15 2004 *************** *** 0 **** --- 1,3199 ---- + //===-- PPC64ISelSimple.cpp - A simple instruction selector 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. + // + //===----------------------------------------------------------------------===// + + #define DEBUG_TYPE "isel" + #include "PowerPC.h" + #include "PowerPCInstrBuilder.h" + #include "PowerPCInstrInfo.h" + #include "PPC64TargetMachine.h" + #include "llvm/Constants.h" + #include "llvm/DerivedTypes.h" + #include "llvm/Function.h" + #include "llvm/Instructions.h" + #include "llvm/Pass.h" + #include "llvm/CodeGen/IntrinsicLowering.h" + #include "llvm/CodeGen/MachineConstantPool.h" + #include "llvm/CodeGen/MachineFrameInfo.h" + #include "llvm/CodeGen/MachineFunction.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 "Support/Debug.h" + #include "Support/Statistic.h" + #include + using namespace llvm; + + namespace { + Statistic<> GEPFolds("ppc64-codegen", "Number of GEPs folded"); + + /// TypeClass - Used by the PowerPC backend to group LLVM types by their basic + /// PPC Representation. + /// + enum TypeClass { + cByte, cShort, cInt, cFP32, cFP64, cLong + }; + } + + /// getClass - Turn a primitive type into a "class" number which is based on the + /// size of the type, and whether or not it is floating point. + /// + static inline TypeClass getClass(const Type *Ty) { + switch (Ty->getTypeID()) { + case Type::SByteTyID: + case Type::UByteTyID: return cByte; // Byte operands are class #0 + case Type::ShortTyID: + case Type::UShortTyID: return cShort; // Short operands are class #1 + case Type::IntTyID: + case Type::UIntTyID: + case Type::PointerTyID: return cInt; // Ints and pointers are class #2 + + case Type::FloatTyID: return cFP32; // Single float is #3 + case Type::DoubleTyID: return cFP64; // Double Point is #4 + + case Type::LongTyID: + case Type::ULongTyID: return cLong; // Longs are class #5 + default: + assert(0 && "Invalid type to getClass!"); + return cByte; // not reached + } + } + + // getClassB - Just like getClass, but treat boolean values as ints. + static inline TypeClass getClassB(const Type *Ty) { + if (Ty == Type::BoolTy) return cInt; + return getClass(Ty); + } + + namespace { + struct ISel : public FunctionPass, InstVisitor { + PPC64TargetMachine &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 + + std::map RegMap; // Mapping between Values and SSA Regs + + // External functions used in the Module + Function *fmodfFn, *fmodFn, *__cmpdi2Fn, *__moddi3Fn, *__divdi3Fn, + *__umoddi3Fn, *__udivdi3Fn, *__fixsfdiFn, *__fixdfdiFn, *__fixunssfdiFn, + *__fixunsdfdiFn, *__floatdisfFn, *__floatdidfFn, *mallocFn, *freeFn; + + // MBBMap - Mapping between LLVM BB -> Machine BB + std::map MBBMap; + + // AllocaMap - Mapping from fixed sized alloca instructions to the + // FrameIndex for the alloca. + std::map AllocaMap; + + // A Reg to hold the base address used for global loads and stores, and a + // flag to set whether or not we need to emit it for this function. + unsigned GlobalBaseReg; + bool GlobalBaseInitialized; + + ISel(TargetMachine &tm) : TM(reinterpret_cast(tm)), + F(0), BB(0) {} + + bool doInitialization(Module &M) { + // Add external functions that we may call + Type *i = Type::IntTy; + Type *d = Type::DoubleTy; + Type *f = Type::FloatTy; + Type *l = Type::LongTy; + Type *ul = Type::ULongTy; + Type *voidPtr = PointerType::get(Type::SByteTy); + // float fmodf(float, float); + fmodfFn = M.getOrInsertFunction("fmodf", f, f, f, 0); + // double fmod(double, double); + fmodFn = M.getOrInsertFunction("fmod", d, d, d, 0); + // int __cmpdi2(long, long); + __cmpdi2Fn = M.getOrInsertFunction("__cmpdi2", i, l, l, 0); + // long __moddi3(long, long); + __moddi3Fn = M.getOrInsertFunction("__moddi3", l, l, l, 0); + // long __divdi3(long, long); + __divdi3Fn = M.getOrInsertFunction("__divdi3", l, l, l, 0); + // unsigned long __umoddi3(unsigned long, unsigned long); + __umoddi3Fn = M.getOrInsertFunction("__umoddi3", ul, ul, ul, 0); + // unsigned long __udivdi3(unsigned long, unsigned long); + __udivdi3Fn = M.getOrInsertFunction("__udivdi3", ul, ul, ul, 0); + // long __fixsfdi(float) + __fixsfdiFn = M.getOrInsertFunction("__fixsfdi", l, f, 0); + // long __fixdfdi(double) + __fixdfdiFn = M.getOrInsertFunction("__fixdfdi", l, d, 0); + // unsigned long __fixunssfdi(float) + __fixunssfdiFn = M.getOrInsertFunction("__fixunssfdi", ul, f, 0); + // unsigned long __fixunsdfdi(double) + __fixunsdfdiFn = M.getOrInsertFunction("__fixunsdfdi", ul, d, 0); + // float __floatdisf(long) + __floatdisfFn = M.getOrInsertFunction("__floatdisf", f, l, 0); + // double __floatdidf(long) + __floatdidfFn = M.getOrInsertFunction("__floatdidf", d, l, 0); + // void* malloc(size_t) + mallocFn = M.getOrInsertFunction("malloc", voidPtr, Type::UIntTy, 0); + // void free(void*) + freeFn = M.getOrInsertFunction("free", Type::VoidTy, voidPtr, 0); + return false; + } + + /// runOnFunction - Top level implementation of instruction selection for + /// the entire function. + /// + bool 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(); + + // Make sure we re-emit a set of the global base reg if necessary + GlobalBaseInitialized = false; + + // Copy incoming arguments off of the stack... + LoadArgumentsToVirtualRegs(Fn); + + // Instruction select everything except PHI nodes + visit(Fn); + + // Select the PHI nodes + SelectPHINodes(); + + RegMap.clear(); + MBBMap.clear(); + AllocaMap.clear(); + F = 0; + // We always build a machine code representation for the function + return true; + } + + virtual const char *getPassName() const { + return "PowerPC 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]; + } + + /// 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 + /// from the stack into virtual registers. + /// + void LoadArgumentsToVirtualRegs(Function &F); + + /// SelectPHINodes - Insert machine code to generate phis. This is tricky + /// because we have to generate our sources into the source basic blocks, + /// not the current one. + /// + void SelectPHINodes(); + + // Visitation methods for various instructions. These methods simply emit + // fixed PowerPC code for each instruction. + + // Control flow operators + void visitReturnInst(ReturnInst &RI); + void visitBranchInst(BranchInst &BI); + + struct ValueRecord { + Value *Val; + unsigned Reg; + const Type *Ty; + ValueRecord(unsigned R, const Type *T) : Val(0), Reg(R), Ty(T) {} + ValueRecord(Value *V) : Val(V), Reg(0), Ty(V->getType()) {} + }; + + // This struct is for recording the necessary operations to emit the GEP + struct CollapsedGepOp { + bool isMul; + Value *index; + ConstantSInt *size; + CollapsedGepOp(bool mul, Value *i, ConstantSInt *s) : + isMul(mul), index(i), size(s) {} + }; + + void doCall(const ValueRecord &Ret, MachineInstr *CallMI, + const std::vector &Args, bool isVarArg); + void visitCallInst(CallInst &I); + void visitIntrinsicCall(Intrinsic::ID ID, CallInst &I); + + // Arithmetic operators + void visitSimpleBinary(BinaryOperator &B, unsigned OpcodeClass); + void visitAdd(BinaryOperator &B) { visitSimpleBinary(B, 0); } + void visitSub(BinaryOperator &B) { visitSimpleBinary(B, 1); } + void visitMul(BinaryOperator &B); + + void visitDiv(BinaryOperator &B) { visitDivRem(B); } + void visitRem(BinaryOperator &B) { visitDivRem(B); } + void visitDivRem(BinaryOperator &B); + + // Bitwise operators + void visitAnd(BinaryOperator &B) { visitSimpleBinary(B, 2); } + void visitOr (BinaryOperator &B) { visitSimpleBinary(B, 3); } + void visitXor(BinaryOperator &B) { visitSimpleBinary(B, 4); } + + // Comparison operators... + void visitSetCondInst(SetCondInst &I); + unsigned EmitComparison(unsigned OpNum, Value *Op0, Value *Op1, + MachineBasicBlock *MBB, + MachineBasicBlock::iterator MBBI); + void visitSelectInst(SelectInst &SI); + + + // Memory Instructions + void visitLoadInst(LoadInst &I); + void visitStoreInst(StoreInst &I); + void visitGetElementPtrInst(GetElementPtrInst &I); + void visitAllocaInst(AllocaInst &I); + void visitMallocInst(MallocInst &I); + void visitFreeInst(FreeInst &I); + + // Other operators + void visitShiftInst(ShiftInst &I); + void visitPHINode(PHINode &I) {} // PHI nodes handled by second pass + void visitCastInst(CastInst &I); + void visitVANextInst(VANextInst &I); + void visitVAArgInst(VAArgInst &I); + + void visitInstruction(Instruction &I) { + std::cerr << "Cannot instruction select: " << I; + abort(); + } + + /// promote32 - Make a value 32-bits wide, and put it somewhere. + /// + void promote32(unsigned targetReg, const ValueRecord &VR); + + /// emitGEPOperation - Common code shared between visitGetElementPtrInst and + /// constant expression GEP support. + /// + void emitGEPOperation(MachineBasicBlock *BB, MachineBasicBlock::iterator IP, + Value *Src, User::op_iterator IdxBegin, + User::op_iterator IdxEnd, unsigned TargetReg, + bool CollapseRemainder, ConstantSInt **Remainder, + unsigned *PendingAddReg); + + /// 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, + unsigned OperatorClass, unsigned TargetReg); + + /// emitBinaryFPOperation - This method handles emission of floating point + /// Add (0), Sub (1), Mul (2), and Div (3) operations. + void emitBinaryFPOperation(MachineBasicBlock *BB, + MachineBasicBlock::iterator IP, + Value *Op0, Value *Op1, + unsigned OperatorClass, unsigned TargetReg); + + void emitMultiply(MachineBasicBlock *BB, MachineBasicBlock::iterator IP, + Value *Op0, Value *Op1, unsigned TargetReg); + + void doMultiply(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + unsigned DestReg, Value *Op0, Value *Op1); + + /// doMultiplyConst - This method will multiply the value in Op0Reg by the + /// value of the ContantInt *CI + void doMultiplyConst(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + unsigned DestReg, Value *Op0, ConstantInt *CI); + + void emitDivRemOperation(MachineBasicBlock *BB, + MachineBasicBlock::iterator IP, + Value *Op0, Value *Op1, bool isDiv, + unsigned TargetReg); + + /// emitSetCCOperation - Common code shared between visitSetCondInst and + /// constant expression support. + /// + void emitSetCCOperation(MachineBasicBlock *BB, + 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, + Value *Op, Value *ShiftAmount, bool isLeftShift, + const Type *ResultTy, unsigned DestReg); + + /// emitSelectOperation - Common code shared between visitSelectInst and the + /// constant expression support. + /// + void emitSelectOperation(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Value *Cond, Value *TrueVal, Value *FalseVal, + unsigned DestReg); + + /// copyGlobalBaseToRegister - Output the instructions required to put the + /// base address to use for accessing globals into a register. + /// + void ISel::copyGlobalBaseToRegister(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + unsigned R); + + /// copyConstantToRegister - Output the instructions required to put the + /// specified constant into the specified register. + /// + void copyConstantToRegister(MachineBasicBlock *MBB, + MachineBasicBlock::iterator MBBI, + Constant *C, unsigned Reg); + + void emitUCOM(MachineBasicBlock *MBB, MachineBasicBlock::iterator MBBI, + unsigned LHS, unsigned RHS); + + /// makeAnotherReg - This method returns the next register number we haven't + /// yet used. + /// + unsigned makeAnotherReg(const Type *Ty) { + assert(dynamic_cast(TM.getRegisterInfo()) && + "Current target doesn't have PPC reg info??"); + const PowerPCRegisterInfo *PPCRI = + static_cast(TM.getRegisterInfo()); + // Add the mapping of regnumber => reg class to MachineFunction + const TargetRegisterClass *RC = PPCRI->getRegClassForType(Ty); + return F->getSSARegMap()->createVirtualRegister(RC); + } + + /// getReg - This method turns an LLVM value into a register number. + /// + unsigned getReg(Value &V) { return getReg(&V); } // Allow references + unsigned getReg(Value *V) { + // Just append to the end of the current bb. + MachineBasicBlock::iterator It = BB->end(); + return getReg(V, BB, It); + } + unsigned getReg(Value *V, MachineBasicBlock *MBB, + MachineBasicBlock::iterator IPt); + + /// canUseAsImmediateForOpcode - This method returns whether a ConstantInt + /// is okay to use as an immediate argument to a certain binary operation + bool canUseAsImmediateForOpcode(ConstantInt *CI, unsigned Opcode); + + /// getFixedSizedAllocaFI - Return the frame index for a fixed sized alloca + /// that is to be statically allocated with the initial stack frame + /// adjustment. + unsigned getFixedSizedAllocaFI(AllocaInst *AI); + }; + } + + /// dyn_castFixedAlloca - If the specified value is a fixed size alloca + /// instruction in the entry block, return it. Otherwise, return a null + /// pointer. + static AllocaInst *dyn_castFixedAlloca(Value *V) { + if (AllocaInst *AI = dyn_cast(V)) { + BasicBlock *BB = AI->getParent(); + if (isa(AI->getArraySize()) && BB ==&BB->getParent()->front()) + return AI; + } + return 0; + } + + /// getReg - This method turns an LLVM value into a register number. + /// + unsigned ISel::getReg(Value *V, MachineBasicBlock *MBB, + MachineBasicBlock::iterator IPt) { + if (Constant *C = dyn_cast(V)) { + unsigned Reg = makeAnotherReg(V->getType()); + copyConstantToRegister(MBB, IPt, C, Reg); + return Reg; + } else if (AllocaInst *AI = dyn_castFixedAlloca(V)) { + unsigned Reg = makeAnotherReg(V->getType()); + unsigned FI = getFixedSizedAllocaFI(AI); + addFrameReference(BuildMI(*MBB, IPt, PPC::ADDI, 2, Reg), FI, 0, false); + return Reg; + } + + unsigned &Reg = RegMap[V]; + if (Reg == 0) { + Reg = makeAnotherReg(V->getType()); + RegMap[V] = Reg; + } + + return Reg; + } + + /// canUseAsImmediateForOpcode - This method returns whether a ConstantInt + /// is okay to use as an immediate argument to a certain binary operator. + /// + /// Operator is one of: 0 for Add, 1 for Sub, 2 for And, 3 for Or, 4 for Xor. + bool ISel::canUseAsImmediateForOpcode(ConstantInt *CI, unsigned Operator) { + ConstantSInt *Op1Cs; + ConstantUInt *Op1Cu; + + // ADDI, Compare, and non-indexed Load take SIMM + bool cond1 = (Operator == 0) + && (Op1Cs = dyn_cast(CI)) + && (Op1Cs->getValue() <= 32767) + && (Op1Cs->getValue() >= -32768); + + // SUBI takes -SIMM since it is a mnemonic for ADDI + bool cond2 = (Operator == 1) + && (Op1Cs = dyn_cast(CI)) + && (Op1Cs->getValue() <= 32768) + && (Op1Cs->getValue() >= -32767); + + // ANDIo, ORI, and XORI take unsigned values + bool cond3 = (Operator >= 2) + && (Op1Cs = dyn_cast(CI)) + && (Op1Cs->getValue() >= 0) + && (Op1Cs->getValue() <= 32767); + + // ADDI and SUBI take SIMMs, so we have to make sure the UInt would fit + bool cond4 = (Operator < 2) + && (Op1Cu = dyn_cast(CI)) + && (Op1Cu->getValue() <= 32767); + + // ANDIo, ORI, and XORI take UIMMs, so they can be larger + bool cond5 = (Operator >= 2) + && (Op1Cu = dyn_cast(CI)) + && (Op1Cu->getValue() <= 65535); + + if (cond1 || cond2 || cond3 || cond4 || cond5) + return true; + + return false; + } + + /// getFixedSizedAllocaFI - Return the frame index for a fixed sized alloca + /// that is to be statically allocated with the initial stack frame + /// adjustment. + unsigned ISel::getFixedSizedAllocaFI(AllocaInst *AI) { + // Already computed this? + std::map::iterator I = AllocaMap.lower_bound(AI); + if (I != AllocaMap.end() && I->first == AI) return I->second; + + const Type *Ty = AI->getAllocatedType(); + ConstantUInt *CUI = cast(AI->getArraySize()); + unsigned TySize = TM.getTargetData().getTypeSize(Ty); + TySize *= CUI->getValue(); // Get total allocated size... + unsigned Alignment = TM.getTargetData().getTypeAlignment(Ty); + + // Create a new stack object using the frame manager... + int FrameIdx = F->getFrameInfo()->CreateStackObject(TySize, Alignment); + AllocaMap.insert(I, std::make_pair(AI, FrameIdx)); + return FrameIdx; + } + + + /// copyGlobalBaseToRegister - Output the instructions required to put the + /// base address to use for accessing globals into a register. + /// + void ISel::copyGlobalBaseToRegister(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + unsigned R) { + if (!GlobalBaseInitialized) { + // Insert the set of GlobalBaseReg into the first MBB of the function + MachineBasicBlock &FirstMBB = F->front(); + MachineBasicBlock::iterator MBBI = FirstMBB.begin(); + GlobalBaseReg = makeAnotherReg(Type::IntTy); + BuildMI(FirstMBB, MBBI, PPC::IMPLICIT_DEF, 0, PPC::LR); + BuildMI(FirstMBB, MBBI, PPC::MovePCtoLR, 0, GlobalBaseReg); + GlobalBaseInitialized = true; + } + // Emit our copy of GlobalBaseReg to the destination register in the + // current MBB + BuildMI(*MBB, IP, PPC::OR, 2, R).addReg(GlobalBaseReg) + .addReg(GlobalBaseReg); + } + + /// copyConstantToRegister - Output the instructions required to put the + /// specified constant into the specified register. + /// + void ISel::copyConstantToRegister(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Constant *C, unsigned R) { + if (C->getType()->isIntegral()) { + unsigned Class = getClassB(C->getType()); + + if (Class == cLong) { + if (ConstantUInt *CUI = dyn_cast(C)) { + uint64_t uval = CUI->getValue(); + if (uval < (1LL << 32)) { + ConstantUInt *CU = ConstantUInt::get(Type::UIntTy, uval); + copyConstantToRegister(MBB, IP, CU, R); + return; + } + } else if (ConstantSInt *CSI = dyn_cast(C)) { + int64_t val = CUI->getValue(); + if (val < (1LL << 31)) { + ConstantUInt *CU = ConstantUInt::get(Type::UIntTy, val); + copyConstantToRegister(MBB, IP, CU, R); + return; + } + } else { + std::cerr << "Unhandled long constant type!\n"; + abort(); + } + // Spill long to the constant pool and load it + MachineConstantPool *CP = F->getConstantPool(); + unsigned CPI = CP->getConstantPoolIndex(C); + BuildMI(*MBB, IP, PPC::LD, 1, R) + .addReg(PPC::R2).addConstantPoolIndex(CPI); + } + + assert(Class <= cInt && "Type not handled yet!"); + + // Handle bool + if (C->getType() == Type::BoolTy) { + BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(C == ConstantBool::True); + return; + } + + // Handle int + if (ConstantUInt *CUI = dyn_cast(C)) { + unsigned uval = CUI->getValue(); + if (uval < 32768) { + BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(uval); + } else { + unsigned Temp = makeAnotherReg(Type::IntTy); + BuildMI(*MBB, IP, PPC::LIS, 1, Temp).addSImm(uval >> 16); + BuildMI(*MBB, IP, PPC::ORI, 2, R).addReg(Temp).addImm(uval); + } + return; + } else if (ConstantSInt *CSI = dyn_cast(C)) { + int sval = CSI->getValue(); + if (sval < 32768 && sval >= -32768) { + BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(sval); + } else { + unsigned Temp = makeAnotherReg(Type::IntTy); + BuildMI(*MBB, IP, PPC::LIS, 1, Temp).addSImm(sval >> 16); + BuildMI(*MBB, IP, PPC::ORI, 2, R).addReg(Temp).addImm(sval); + } + return; + } + std::cerr << "Unhandled integer constant!\n"; + abort(); + } else if (ConstantFP *CFP = dyn_cast(C)) { + // We need to spill the constant to memory... + MachineConstantPool *CP = F->getConstantPool(); + unsigned CPI = CP->getConstantPoolIndex(CFP); + const Type *Ty = CFP->getType(); + unsigned LoadOpcode = (Ty == Type::FloatTy) ? PPC::LFS : PPC::LFD; + BuildMI(*MBB,IP,LoadOpcode,2,R).addConstantPoolIndex(CPI).addReg(PPC::R2); + } else if (isa(C)) { + // Copy zero (null pointer) to the register. + BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(0); + } else if (GlobalValue *GV = dyn_cast(C)) { + unsigned TmpReg = makeAnotherReg(GV->getType()); + BuildMI(*MBB, IP, PPC::LD, 2, TmpReg).addGlobalAddress(GV).addReg(PPC::R2); + BuildMI(*MBB, IP, PPC::LWA, 2, R).addSImm(0).addReg(TmpReg); + } else { + std::cerr << "Offending constant: " << *C << "\n"; + assert(0 && "Type not handled yet!"); + } + } + + /// LoadArgumentsToVirtualRegs - Load all of the arguments to this function from + /// the stack into virtual registers. + void ISel::LoadArgumentsToVirtualRegs(Function &Fn) { + unsigned ArgOffset = 24; + unsigned GPR_remaining = 8; + unsigned FPR_remaining = 13; + unsigned GPR_idx = 0, FPR_idx = 0; + static const unsigned GPR[] = { + PPC::R3, PPC::R4, PPC::R5, PPC::R6, + PPC::R7, PPC::R8, PPC::R9, PPC::R10, + }; + static const unsigned FPR[] = { + PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, PPC::F7, + PPC::F8, PPC::F9, PPC::F10, PPC::F11, PPC::F12, PPC::F13 + }; + + MachineFrameInfo *MFI = F->getFrameInfo(); + + for (Function::aiterator I = Fn.abegin(), E = Fn.aend(); I != E; ++I) { + bool ArgLive = !I->use_empty(); + unsigned Reg = ArgLive ? getReg(*I) : 0; + int FI; // Frame object index + + switch (getClassB(I->getType())) { + case cByte: + if (ArgLive) { + FI = MFI->CreateFixedObject(4, ArgOffset); + if (GPR_remaining > 0) { + BuildMI(BB, PPC::IMPLICIT_DEF, 0, GPR[GPR_idx]); + BuildMI(BB, PPC::OR, 2, Reg).addReg(GPR[GPR_idx]) + .addReg(GPR[GPR_idx]); + } else { + addFrameReference(BuildMI(BB, PPC::LBZ, 2, Reg), FI); + } + } + break; + case cShort: + if (ArgLive) { + FI = MFI->CreateFixedObject(4, ArgOffset); + if (GPR_remaining > 0) { + BuildMI(BB, PPC::IMPLICIT_DEF, 0, GPR[GPR_idx]); + BuildMI(BB, PPC::OR, 2, Reg).addReg(GPR[GPR_idx]) + .addReg(GPR[GPR_idx]); + } else { + addFrameReference(BuildMI(BB, PPC::LHZ, 2, Reg), FI); + } + } + break; + case cInt: + if (ArgLive) { + FI = MFI->CreateFixedObject(4, ArgOffset); + if (GPR_remaining > 0) { + BuildMI(BB, PPC::IMPLICIT_DEF, 0, GPR[GPR_idx]); + BuildMI(BB, PPC::OR, 2, Reg).addReg(GPR[GPR_idx]) + .addReg(GPR[GPR_idx]); + } else { + addFrameReference(BuildMI(BB, PPC::LWZ, 2, Reg), FI); + } + } + break; + case cLong: + if (ArgLive) { + FI = MFI->CreateFixedObject(8, ArgOffset); + if (GPR_remaining > 1) { + BuildMI(BB, PPC::IMPLICIT_DEF, 0, GPR[GPR_idx]); + BuildMI(BB, PPC::OR, 2, Reg).addReg(GPR[GPR_idx]) + .addReg(GPR[GPR_idx]); + } else { + addFrameReference(BuildMI(BB, PPC::LD, 2, Reg), FI); + } + } + // longs require 4 additional bytes + ArgOffset += 4; + break; + case cFP32: + if (ArgLive) { + FI = MFI->CreateFixedObject(4, ArgOffset); + + if (FPR_remaining > 0) { + BuildMI(BB, PPC::IMPLICIT_DEF, 0, FPR[FPR_idx]); + BuildMI(BB, PPC::FMR, 1, Reg).addReg(FPR[FPR_idx]); + FPR_remaining--; + FPR_idx++; + } else { + addFrameReference(BuildMI(BB, PPC::LFS, 2, Reg), FI); + } + } + break; + case cFP64: + if (ArgLive) { + FI = MFI->CreateFixedObject(8, ArgOffset); + + if (FPR_remaining > 0) { + BuildMI(BB, PPC::IMPLICIT_DEF, 0, FPR[FPR_idx]); + BuildMI(BB, PPC::FMR, 1, Reg).addReg(FPR[FPR_idx]); + FPR_remaining--; + FPR_idx++; + } else { + addFrameReference(BuildMI(BB, PPC::LFD, 2, Reg), FI); + } + } + + // doubles require 4 additional bytes and use 2 GPRs of param space + ArgOffset += 4; + if (GPR_remaining > 0) { + GPR_remaining--; + GPR_idx++; + } + break; + default: + assert(0 && "Unhandled argument type!"); + } + ArgOffset += 4; // Each argument takes at least 4 bytes on the stack... + if (GPR_remaining > 0) { + GPR_remaining--; // uses up 2 GPRs + GPR_idx++; + } + } + + // If the function takes variable number of arguments, add a frame offset for + // the start of the first vararg value... this is used to expand + // llvm.va_start. + if (Fn.getFunctionType()->isVarArg()) + VarArgsFrameIndex = MFI->CreateFixedObject(4, ArgOffset); + } + + + /// SelectPHINodes - Insert machine code to generate phis. This is tricky + /// because we have to generate our sources into the source basic blocks, not + /// the current one. + /// + void ISel::SelectPHINodes() { + const TargetInstrInfo &TII = *TM.getInstrInfo(); + 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]; + + // Loop over all of the PHI nodes in the LLVM basic block... + 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(MBB, PHIInsertPoint, + PPC::PHI, PN->getNumOperands(), PHIReg); + + // PHIValues - Map of blocks to incoming virtual registers. We use this + // so that we only initialize one incoming value for a particular block, + // even if the block has multiple entries in the PHI node. + // + std::map PHIValues; + + for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { + MachineBasicBlock *PredMBB = 0; + for (MachineBasicBlock::pred_iterator PI = MBB.pred_begin (), + PE = MBB.pred_end (); PI != PE; ++PI) + if (PN->getIncomingBlock(i) == (*PI)->getBasicBlock()) { + PredMBB = *PI; + break; + } + assert (PredMBB && "Couldn't find incoming machine-cfg edge for phi"); + + unsigned ValReg; + std::map::iterator EntryIt = + PHIValues.lower_bound(PredMBB); + + if (EntryIt != PHIValues.end() && EntryIt->first == PredMBB) { + // We already inserted an initialization of the register for this + // predecessor. Recycle it. + ValReg = EntryIt->second; + } else { + // Get the incoming value into a virtual register. + // + Value *Val = PN->getIncomingValue(i); + + // If this is a constant or GlobalValue, we may have to insert code + // into the basic block to compute it into a virtual register. + if ((isa(Val) && !isa(Val)) || + isa(Val)) { + // Simple constants get emitted at the end of the basic block, + // before any terminator instructions. We "know" that the code to + // move a constant into a register will never clobber any flags. + ValReg = getReg(Val, PredMBB, PredMBB->getFirstTerminator()); + } else { + // Because we don't want to clobber any values which might be in + // physical registers with the computation of this constant (which + // might be arbitrarily complex if it is a constant expression), + // just insert the computation at the top of the basic block. + MachineBasicBlock::iterator PI = PredMBB->begin(); + + // Skip over any PHI nodes though! + while (PI != PredMBB->end() && PI->getOpcode() == PPC::PHI) + ++PI; + + ValReg = getReg(Val, PredMBB, PI); + } + + // Remember that we inserted a value for this PHI for this predecessor + PHIValues.insert(EntryIt, std::make_pair(PredMBB, ValReg)); + } + + PhiMI->addRegOperand(ValReg); + PhiMI->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 = PhiMI; + ++PHIInsertPoint; + } + } + } + + + // canFoldSetCCIntoBranchOrSelect - Return the setcc instruction if we can fold + // it into the conditional branch or select instruction which is the only user + // of the cc instruction. This is the case if the conditional branch is the + // only user of the setcc, and if the setcc is in the same basic block as the + // conditional branch. + // + static SetCondInst *canFoldSetCCIntoBranchOrSelect(Value *V) { + if (SetCondInst *SCI = dyn_cast(V)) + if (SCI->hasOneUse()) { + Instruction *User = cast(SCI->use_back()); + if ((isa(User) || isa(User)) && + SCI->getParent() == User->getParent()) + return SCI; + } + return 0; + } + + + // canFoldGEPIntoLoadOrStore - Return the GEP instruction if we can fold it into + // the load or store instruction that is the only user of the GEP. + // + static GetElementPtrInst *canFoldGEPIntoLoadOrStore(Value *V) { + if (GetElementPtrInst *GEPI = dyn_cast(V)) + if (GEPI->hasOneUse()) { + Instruction *User = cast(GEPI->use_back()); + if (isa(User) && + GEPI->getParent() == User->getParent() && + User->getOperand(0) != GEPI && + User->getOperand(1) == GEPI) { + ++GEPFolds; + return GEPI; + } + if (isa(User) && + GEPI->getParent() == User->getParent() && + User->getOperand(0) == GEPI) { + ++GEPFolds; + return GEPI; + } + } + return 0; + } + + + // Return a fixed numbering for setcc instructions which does not depend on the + // order of the opcodes. + // + static unsigned getSetCCNumber(unsigned Opcode) { + switch (Opcode) { + default: assert(0 && "Unknown setcc instruction!"); + case Instruction::SetEQ: return 0; + case Instruction::SetNE: return 1; + case Instruction::SetLT: return 2; + case Instruction::SetGE: return 3; + case Instruction::SetGT: return 4; + case Instruction::SetLE: return 5; + } + } + + static unsigned getPPCOpcodeForSetCCNumber(unsigned Opcode) { + switch (Opcode) { + default: assert(0 && "Unknown setcc instruction!"); + case Instruction::SetEQ: return PPC::BEQ; + case Instruction::SetNE: return PPC::BNE; + case Instruction::SetLT: return PPC::BLT; + case Instruction::SetGE: return PPC::BGE; + case Instruction::SetGT: return PPC::BGT; + case Instruction::SetLE: return PPC::BLE; + } + } + + /// emitUCOM - emits an unordered FP compare. + void ISel::emitUCOM(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP, + unsigned LHS, unsigned RHS) { + BuildMI(*MBB, IP, PPC::FCMPU, 2, PPC::CR0).addReg(LHS).addReg(RHS); + } + + /// EmitComparison - emits a comparison of the two operands, returning the + /// extended setcc code to use. The result is in CR0. + /// + unsigned ISel::EmitComparison(unsigned OpNum, Value *Op0, Value *Op1, + MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP) { + // The arguments are already supposed to be of the same type. + const Type *CompTy = Op0->getType(); + unsigned Class = getClassB(CompTy); + unsigned Op0r = getReg(Op0, MBB, IP); + + // Before we do a comparison, we have to make sure that we're truncating our + // registers appropriately. + if (Class == cByte) { + unsigned TmpReg = makeAnotherReg(CompTy); + if (CompTy->isSigned()) + BuildMI(*MBB, IP, PPC::EXTSB, 1, TmpReg).addReg(Op0r); + else + BuildMI(*MBB, IP, PPC::RLWINM, 4, TmpReg).addReg(Op0r).addImm(0) + .addImm(24).addImm(31); + Op0r = TmpReg; + } else if (Class == cShort) { + unsigned TmpReg = makeAnotherReg(CompTy); + if (CompTy->isSigned()) + BuildMI(*MBB, IP, PPC::EXTSH, 1, TmpReg).addReg(Op0r); + else + BuildMI(*MBB, IP, PPC::RLWINM, 4, TmpReg).addReg(Op0r).addImm(0) + .addImm(16).addImm(31); + Op0r = TmpReg; + } + + // Use crand for lt, gt and crandc for le, ge + unsigned CROpcode = (OpNum == 2 || OpNum == 4) ? PPC::CRAND : PPC::CRANDC; + unsigned Opcode = CompTy->isSigned() ? PPC::CMPW : PPC::CMPLW; + unsigned OpcodeImm = CompTy->isSigned() ? PPC::CMPWI : PPC::CMPLWI; + if (Class == cLong) { + Opcode = CompTy->isSigned() ? PPC::CMPD : PPC::CMPLD; + OpcodeImm = CompTy->isSigned() ? PPC::CMPDI : PPC::CMPLDI; + } + + // Special case handling of: cmp R, i + if (ConstantInt *CI = dyn_cast(Op1)) { + unsigned Op1v = CI->getRawValue() & 0xFFFF; + + // Treat compare like ADDI for the purposes of immediate suitability + if (canUseAsImmediateForOpcode(CI, 0)) { + BuildMI(*MBB, IP, OpcodeImm, 2, PPC::CR0).addReg(Op0r).addSImm(Op1v); + } else { + unsigned Op1r = getReg(Op1, MBB, IP); + BuildMI(*MBB, IP, Opcode, 2, PPC::CR0).addReg(Op0r).addReg(Op1r); + } + return OpNum; + } + + unsigned Op1r = getReg(Op1, MBB, IP); + + switch (Class) { + default: assert(0 && "Unknown type class!"); + case cByte: + case cShort: + case cInt: + case cLong: + BuildMI(*MBB, IP, Opcode, 2, PPC::CR0).addReg(Op0r).addReg(Op1r); + break; + + case cFP32: + case cFP64: + emitUCOM(MBB, IP, Op0r, Op1r); + break; + } + + return OpNum; + } + + /// visitSetCondInst - emit code to calculate the condition via + /// EmitComparison(), and possibly store a 0 or 1 to a register as a result + /// + void ISel::visitSetCondInst(SetCondInst &I) { + if (canFoldSetCCIntoBranchOrSelect(&I)) + return; + + unsigned DestReg = getReg(I); + unsigned OpNum = I.getOpcode(); + const Type *Ty = I.getOperand (0)->getType(); + + EmitComparison(OpNum, I.getOperand(0), I.getOperand(1), BB, BB->end()); + + unsigned Opcode = getPPCOpcodeForSetCCNumber(OpNum); + MachineBasicBlock *thisMBB = BB; + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + ilist::iterator It = BB; + ++It; + + // thisMBB: + // ... + // cmpTY cr0, r1, r2 + // bCC copy1MBB + // b copy0MBB + + // FIXME: we wouldn't need copy0MBB (we could fold it into thisMBB) + // if we could insert other, non-terminator instructions after the + // bCC. But MBB->getFirstTerminator() can't understand this. + MachineBasicBlock *copy1MBB = new MachineBasicBlock(LLVM_BB); + F->getBasicBlockList().insert(It, copy1MBB); + BuildMI(BB, Opcode, 2).addReg(PPC::CR0).addMBB(copy1MBB); + MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB); + F->getBasicBlockList().insert(It, copy0MBB); + BuildMI(BB, PPC::B, 1).addMBB(copy0MBB); + MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB); + F->getBasicBlockList().insert(It, sinkMBB); + // Update machine-CFG edges + BB->addSuccessor(copy1MBB); + BB->addSuccessor(copy0MBB); + + // copy1MBB: + // %TrueValue = li 1 + // b sinkMBB + BB = copy1MBB; + unsigned TrueValue = makeAnotherReg(I.getType()); + BuildMI(BB, PPC::LI, 1, TrueValue).addSImm(1); + BuildMI(BB, PPC::B, 1).addMBB(sinkMBB); + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // copy0MBB: + // %FalseValue = li 0 + // fallthrough + BB = copy0MBB; + unsigned FalseValue = makeAnotherReg(I.getType()); + BuildMI(BB, PPC::LI, 1, FalseValue).addSImm(0); + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, copy1MBB ] + // ... + BB = sinkMBB; + BuildMI(BB, PPC::PHI, 4, DestReg).addReg(FalseValue) + .addMBB(copy0MBB).addReg(TrueValue).addMBB(copy1MBB); + } + + void ISel::visitSelectInst(SelectInst &SI) { + unsigned DestReg = getReg(SI); + MachineBasicBlock::iterator MII = BB->end(); + emitSelectOperation(BB, MII, SI.getCondition(), SI.getTrueValue(), + SI.getFalseValue(), DestReg); + } + + /// emitSelect - Common code shared between visitSelectInst and the constant + /// expression support. + /// FIXME: this is most likely broken in one or more ways. Namely, PowerPC has + /// no select instruction. FSEL only works for comparisons against zero. + void ISel::emitSelectOperation(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Value *Cond, Value *TrueVal, Value *FalseVal, + unsigned DestReg) { + unsigned SelectClass = getClassB(TrueVal->getType()); + unsigned Opcode; + + // See if we can fold the setcc into the select instruction, or if we have + // to get the register of the Cond value + if (SetCondInst *SCI = canFoldSetCCIntoBranchOrSelect(Cond)) { + // We successfully folded the setcc into the select instruction. + unsigned OpNum = getSetCCNumber(SCI->getOpcode()); + OpNum = EmitComparison(OpNum, SCI->getOperand(0),SCI->getOperand(1),MBB,IP); + Opcode = getPPCOpcodeForSetCCNumber(SCI->getOpcode()); + } else { + unsigned CondReg = getReg(Cond, MBB, IP); + BuildMI(*MBB, IP, PPC::CMPI, 2, PPC::CR0).addReg(CondReg).addSImm(0); + Opcode = getPPCOpcodeForSetCCNumber(Instruction::SetNE); + } + + // thisMBB: + // ... + // cmpTY cr0, r1, r2 + // bCC copy1MBB + // b copy0MBB + + MachineBasicBlock *thisMBB = BB; + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + ilist::iterator It = BB; + ++It; + + // FIXME: we wouldn't need copy0MBB (we could fold it into thisMBB) + // if we could insert other, non-terminator instructions after the + // bCC. But MBB->getFirstTerminator() can't understand this. + MachineBasicBlock *copy1MBB = new MachineBasicBlock(LLVM_BB); + F->getBasicBlockList().insert(It, copy1MBB); + BuildMI(BB, Opcode, 2).addReg(PPC::CR0).addMBB(copy1MBB); + MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB); + F->getBasicBlockList().insert(It, copy0MBB); + BuildMI(BB, PPC::B, 1).addMBB(copy0MBB); + MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB); + F->getBasicBlockList().insert(It, sinkMBB); + // Update machine-CFG edges + BB->addSuccessor(copy1MBB); + BB->addSuccessor(copy0MBB); + + // copy1MBB: + // %TrueValue = ... + // b sinkMBB + BB = copy1MBB; + unsigned TrueValue = getReg(TrueVal, BB, BB->begin()); + BuildMI(BB, PPC::B, 1).addMBB(sinkMBB); + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // copy0MBB: + // %FalseValue = ... + // fallthrough + BB = copy0MBB; + unsigned FalseValue = getReg(FalseVal, BB, BB->begin()); + // Update machine-CFG edges + BB->addSuccessor(sinkMBB); + + // sinkMBB: + // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, copy1MBB ] + // ... + BB = sinkMBB; + BuildMI(BB, PPC::PHI, 4, DestReg).addReg(FalseValue) + .addMBB(copy0MBB).addReg(TrueValue).addMBB(copy1MBB); + return; + } + + + + /// 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() || VR.Ty == Type::BoolTy; + + Value *Val = VR.Val; + const Type *Ty = VR.Ty; + if (Val) { + if (Constant *C = dyn_cast(Val)) { + Val = ConstantExpr::getCast(C, Type::IntTy); + if (isa(Val)) // Could not fold + Val = C; + else + Ty = Type::IntTy; // Folded! + } + + // If this is a simple constant, just emit a load directly to avoid the copy + if (ConstantInt *CI = dyn_cast(Val)) { + int TheVal = CI->getRawValue() & 0xFFFFFFFF; + + if (TheVal < 32768 && TheVal >= -32768) { + BuildMI(BB, PPC::LI, 1, targetReg).addSImm(TheVal); + } else { + unsigned TmpReg = makeAnotherReg(Type::IntTy); + BuildMI(BB, PPC::LIS, 1, TmpReg).addSImm(TheVal >> 16); + BuildMI(BB, PPC::ORI, 2, targetReg).addReg(TmpReg) + .addImm(TheVal & 0xFFFF); + } + return; + } + } + + // Make sure we have the register number for this value... + unsigned Reg = Val ? getReg(Val) : VR.Reg; + switch (getClassB(Ty)) { + case cByte: + // Extend value into target register (8->32) + if (isUnsigned) + BuildMI(BB, PPC::RLWINM, 4, targetReg).addReg(Reg).addZImm(0) + .addZImm(24).addZImm(31); + else + BuildMI(BB, PPC::EXTSB, 1, targetReg).addReg(Reg); + break; + case cShort: + // Extend value into target register (16->32) + if (isUnsigned) + BuildMI(BB, PPC::RLWINM, 4, targetReg).addReg(Reg).addZImm(0) + .addZImm(16).addZImm(31); + else + BuildMI(BB, PPC::EXTSH, 1, targetReg).addReg(Reg); + break; + case cInt: + case cLong: + // Move value into target register (32->32) + BuildMI(BB, PPC::OR, 2, targetReg).addReg(Reg).addReg(Reg); + break; + default: + assert(0 && "Unpromotable operand class in promote32"); + } + } + + /// visitReturnInst - implemented with BLR + /// + void ISel::visitReturnInst(ReturnInst &I) { + // Only do the processing if this is a non-void return + if (I.getNumOperands() > 0) { + Value *RetVal = I.getOperand(0); + switch (getClassB(RetVal->getType())) { + case cByte: // integral return values: extend or move into r3 and return + case cShort: + case cInt: + case cLong: + promote32(PPC::R3, ValueRecord(RetVal)); + break; + case cFP32: + case cFP64: { // Floats & Doubles: Return in f1 + unsigned RetReg = getReg(RetVal); + BuildMI(BB, PPC::FMR, 1, PPC::F1).addReg(RetReg); + break; + } + default: + visitInstruction(I); + } + } + BuildMI(BB, PPC::BLR, 1).addImm(0); + } + + // getBlockAfter - Return the basic block which occurs lexically after the + // specified one. + static inline BasicBlock *getBlockAfter(BasicBlock *BB) { + Function::iterator I = BB; ++I; // Get iterator to next block + return I != BB->getParent()->end() ? &*I : 0; + } + + /// visitBranchInst - Handle conditional and unconditional branches here. Note + /// that since code layout is frozen at this point, that if we are trying to + /// jump to a block that is the immediate successor of the current block, we can + /// just make a fall-through (but we don't currently). + /// + void ISel::visitBranchInst(BranchInst &BI) { + // Update machine-CFG edges + BB->addSuccessor(MBBMap[BI.getSuccessor(0)]); + if (BI.isConditional()) + BB->addSuccessor(MBBMap[BI.getSuccessor(1)]); + + BasicBlock *NextBB = getBlockAfter(BI.getParent()); // BB after current one + + if (!BI.isConditional()) { // Unconditional branch? + if (BI.getSuccessor(0) != NextBB) + BuildMI(BB, PPC::B, 1).addMBB(MBBMap[BI.getSuccessor(0)]); + return; + } + + // See if we can fold the setcc into the branch itself... + SetCondInst *SCI = canFoldSetCCIntoBranchOrSelect(BI.getCondition()); + if (SCI == 0) { + // Nope, cannot fold setcc into this branch. Emit a branch on a condition + // computed some other way... + unsigned condReg = getReg(BI.getCondition()); + BuildMI(BB, PPC::CMPLI, 3, PPC::CR0).addImm(0).addReg(condReg) + .addImm(0); + if (BI.getSuccessor(1) == NextBB) { + if (BI.getSuccessor(0) != NextBB) + BuildMI(BB, PPC::COND_BRANCH, 3).addReg(PPC::CR0).addImm(PPC::BNE) + .addMBB(MBBMap[BI.getSuccessor(0)]) + .addMBB(MBBMap[BI.getSuccessor(1)]); + } else { + BuildMI(BB, PPC::COND_BRANCH, 3).addReg(PPC::CR0).addImm(PPC::BEQ) + .addMBB(MBBMap[BI.getSuccessor(1)]) + .addMBB(MBBMap[BI.getSuccessor(0)]); + if (BI.getSuccessor(0) != NextBB) + BuildMI(BB, PPC::B, 1).addMBB(MBBMap[BI.getSuccessor(0)]); + } + return; + } + + unsigned OpNum = getSetCCNumber(SCI->getOpcode()); + unsigned Opcode = getPPCOpcodeForSetCCNumber(SCI->getOpcode()); + MachineBasicBlock::iterator MII = BB->end(); + OpNum = EmitComparison(OpNum, SCI->getOperand(0), SCI->getOperand(1), BB,MII); + + if (BI.getSuccessor(0) != NextBB) { + BuildMI(BB, PPC::COND_BRANCH, 3).addReg(PPC::CR0).addImm(Opcode) + .addMBB(MBBMap[BI.getSuccessor(0)]) + .addMBB(MBBMap[BI.getSuccessor(1)]); + if (BI.getSuccessor(1) != NextBB) + BuildMI(BB, PPC::B, 1).addMBB(MBBMap[BI.getSuccessor(1)]); + } else { + // Change to the inverse condition... + if (BI.getSuccessor(1) != NextBB) { + Opcode = PowerPCInstrInfo::invertPPCBranchOpcode(Opcode); + BuildMI(BB, PPC::COND_BRANCH, 3).addReg(PPC::CR0).addImm(Opcode) + .addMBB(MBBMap[BI.getSuccessor(1)]) + .addMBB(MBBMap[BI.getSuccessor(0)]); + } + } + } + + /// doCall - This emits an abstract call instruction, setting up the arguments + /// and the return value as appropriate. For the actual function call itself, + /// it inserts the specified CallMI instruction into the stream. + /// + void ISel::doCall(const ValueRecord &Ret, MachineInstr *CallMI, + const std::vector &Args, bool isVarArg) { + // Count how many bytes are to be pushed on the stack, including the linkage + // area, and parameter passing area. + unsigned NumBytes = 24; + unsigned ArgOffset = 24; + + if (!Args.empty()) { + for (unsigned i = 0, e = Args.size(); i != e; ++i) + switch (getClassB(Args[i].Ty)) { + case cByte: case cShort: case cInt: + NumBytes += 4; break; + case cLong: + NumBytes += 8; break; + case cFP32: + NumBytes += 4; break; + case cFP64: + NumBytes += 8; break; + break; + default: assert(0 && "Unknown class!"); + } + + // Just to be safe, we'll always reserve the full 32 bytes worth of + // argument passing space in case any called code gets funky on us. + if (NumBytes < 24 + 32) NumBytes = 24 + 32; + + // Adjust the stack pointer for the new arguments... + // These functions are automatically eliminated by the prolog/epilog pass + BuildMI(BB, PPC::ADJCALLSTACKDOWN, 1).addImm(NumBytes); + + // Arguments go on the stack in reverse order, as specified by the ABI. + // Offset to the paramater area on the stack is 24. + int GPR_remaining = 8, FPR_remaining = 13; + unsigned GPR_idx = 0, FPR_idx = 0; + static const unsigned GPR[] = { + PPC::R3, PPC::R4, PPC::R5, PPC::R6, + PPC::R7, PPC::R8, PPC::R9, PPC::R10, + }; + static const unsigned FPR[] = { + PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, + PPC::F7, PPC::F8, PPC::F9, PPC::F10, PPC::F11, PPC::F12, + PPC::F13 + }; + + for (unsigned i = 0, e = Args.size(); i != e; ++i) { + unsigned ArgReg; + switch (getClassB(Args[i].Ty)) { + case cByte: + case cShort: + // Promote arg to 32 bits wide into a temporary register... + ArgReg = makeAnotherReg(Type::UIntTy); + promote32(ArgReg, Args[i]); + + // Reg or stack? + if (GPR_remaining > 0) { + BuildMI(BB, PPC::OR, 2, GPR[GPR_idx]).addReg(ArgReg) + .addReg(ArgReg); + CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use); + } + if (GPR_remaining <= 0 || isVarArg) { + BuildMI(BB, PPC::STW, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); + } + break; + case cInt: + ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; + + // Reg or stack? + if (GPR_remaining > 0) { + BuildMI(BB, PPC::OR, 2, GPR[GPR_idx]).addReg(ArgReg) + .addReg(ArgReg); + CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use); + } + if (GPR_remaining <= 0 || isVarArg) { + BuildMI(BB, PPC::STW, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); + } + break; + case cLong: + ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; + + // Reg or stack? + if (GPR_remaining > 0) { + BuildMI(BB, PPC::OR, 2, GPR[GPR_idx]).addReg(ArgReg) + .addReg(ArgReg); + CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use); + } + if (GPR_remaining <= 0 || isVarArg) { + BuildMI(BB, PPC::STD, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); + } + ArgOffset += 4; // 8 byte entry, not 4. + break; + case cFP32: + ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; + // Reg or stack? + if (FPR_remaining > 0) { + BuildMI(BB, PPC::FMR, 1, FPR[FPR_idx]).addReg(ArgReg); + CallMI->addRegOperand(FPR[FPR_idx], MachineOperand::Use); + FPR_remaining--; + FPR_idx++; + + // If this is a vararg function, and there are GPRs left, also + // pass the float in an int. Otherwise, put it on the stack. + if (isVarArg) { + BuildMI(BB, PPC::STFS, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); + if (GPR_remaining > 0) { + BuildMI(BB, PPC::LWZ, 2, GPR[GPR_idx]) + .addSImm(ArgOffset).addReg(ArgReg); + CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use); + } + } + } else { + BuildMI(BB, PPC::STFS, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); + } + break; + case cFP64: + ArgReg = Args[i].Val ? getReg(Args[i].Val) : Args[i].Reg; + // Reg or stack? + if (FPR_remaining > 0) { + BuildMI(BB, PPC::FMR, 1, FPR[FPR_idx]).addReg(ArgReg); + CallMI->addRegOperand(FPR[FPR_idx], MachineOperand::Use); + FPR_remaining--; + FPR_idx++; + // For vararg functions, must pass doubles via int regs as well + if (isVarArg) { + BuildMI(BB, PPC::STFD, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); + + if (GPR_remaining > 0) { + BuildMI(BB, PPC::LD, 2, GPR[GPR_idx]).addSImm(ArgOffset) + .addReg(PPC::R1); + CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use); + } + } + } else { + BuildMI(BB, PPC::STFD, 3).addReg(ArgReg).addSImm(ArgOffset) + .addReg(PPC::R1); + } + // Doubles use 8 bytes + ArgOffset += 4; + break; + + default: assert(0 && "Unknown class!"); + } + ArgOffset += 4; + GPR_remaining--; + GPR_idx++; + } + } else { + BuildMI(BB, PPC::ADJCALLSTACKDOWN, 1).addImm(0); + } + + BuildMI(BB, PPC::IMPLICIT_DEF, 0, PPC::LR); + BB->push_back(CallMI); + BuildMI(BB, PPC::NOP, 1).addImm(0); + + // These functions are automatically eliminated by the prolog/epilog pass + BuildMI(BB, PPC::ADJCALLSTACKUP, 1).addImm(NumBytes); + + // If there is a return value, scavenge the result from the location the call + // leaves it in... + // + if (Ret.Ty != Type::VoidTy) { + unsigned DestClass = getClassB(Ret.Ty); + switch (DestClass) { + case cByte: + case cShort: + case cInt: + case cLong: + // Integral results are in r3 + BuildMI(BB, PPC::OR, 2, Ret.Reg).addReg(PPC::R3).addReg(PPC::R3); + break; + case cFP32: // Floating-point return values live in f1 + case cFP64: + BuildMI(BB, PPC::FMR, 1, Ret.Reg).addReg(PPC::F1); + break; + default: assert(0 && "Unknown class!"); + } + } + } + + + /// visitCallInst - Push args on stack and do a procedure call instruction. + void ISel::visitCallInst(CallInst &CI) { + MachineInstr *TheCall; + Function *F = CI.getCalledFunction(); + if (F) { + // Is it an intrinsic function call? + if (Intrinsic::ID ID = (Intrinsic::ID)F->getIntrinsicID()) { + visitIntrinsicCall(ID, CI); // Special intrinsics are not handled here + return; + } + // Emit a CALL instruction with PC-relative displacement. + TheCall = BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(F, true); + // Add it to the set of functions called to be used by the Printer + TM.CalledFunctions.insert(F); + } else { // Emit an indirect call through the CTR + unsigned Reg = getReg(CI.getCalledValue()); + BuildMI(BB, PPC::MTCTR, 1).addReg(Reg); + TheCall = BuildMI(PPC::CALLindirect, 2).addZImm(20).addZImm(0); + } + + std::vector Args; + for (unsigned i = 1, e = CI.getNumOperands(); i != e; ++i) + Args.push_back(ValueRecord(CI.getOperand(i))); + + unsigned DestReg = CI.getType() != Type::VoidTy ? getReg(CI) : 0; + bool isVarArg = F ? F->getFunctionType()->isVarArg() : true; + doCall(ValueRecord(DestReg, CI.getType()), TheCall, Args, isVarArg); + } + + + /// dyncastIsNan - Return the operand of an isnan operation if this is an isnan. + /// + static Value *dyncastIsNan(Value *V) { + if (CallInst *CI = dyn_cast(V)) + if (Function *F = CI->getCalledFunction()) + if (F->getIntrinsicID() == Intrinsic::isunordered) + return CI->getOperand(1); + return 0; + } + + /// isOnlyUsedByUnorderedComparisons - Return true if this value is only used by + /// or's whos operands are all calls to the isnan predicate. + static bool isOnlyUsedByUnorderedComparisons(Value *V) { + assert(dyncastIsNan(V) && "The value isn't an isnan call!"); + + // Check all uses, which will be or's of isnans if this predicate is true. + for (Value::use_iterator UI = V->use_begin(), E = V->use_end(); UI != E;++UI){ + Instruction *I = cast(*UI); + if (I->getOpcode() != Instruction::Or) return false; + if (I->getOperand(0) != V && !dyncastIsNan(I->getOperand(0))) return false; + if (I->getOperand(1) != V && !dyncastIsNan(I->getOperand(1))) return false; + } + + return true; + } + + /// 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; ) + if (CallInst *CI = dyn_cast(I++)) + if (Function *F = CI->getCalledFunction()) + switch (F->getIntrinsicID()) { + case Intrinsic::not_intrinsic: + case Intrinsic::vastart: + case Intrinsic::vacopy: + case Intrinsic::vaend: + case Intrinsic::returnaddress: + case Intrinsic::frameaddress: + // FIXME: should lower these ourselves + // case Intrinsic::isunordered: + // case Intrinsic::memcpy: -> doCall(). system memcpy almost + // guaranteed to be faster than anything we generate ourselves + // We directly implement these intrinsics + break; + case Intrinsic::readio: { + // On PPC, memory operations are in-order. Lower this intrinsic + // into a volatile load. + Instruction *Before = CI->getPrev(); + LoadInst * LI = new LoadInst(CI->getOperand(1), "", true, CI); + CI->replaceAllUsesWith(LI); + BB->getInstList().erase(CI); + break; + } + case Intrinsic::writeio: { + // On PPC, memory operations are in-order. Lower this intrinsic + // into a volatile store. + Instruction *Before = CI->getPrev(); + StoreInst *SI = new StoreInst(CI->getOperand(1), + CI->getOperand(2), true, CI); + CI->replaceAllUsesWith(SI); + BB->getInstList().erase(CI); + 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 ISel::visitIntrinsicCall(Intrinsic::ID ID, CallInst &CI) { + unsigned TmpReg1, TmpReg2, TmpReg3; + switch (ID) { + case Intrinsic::vastart: + // Get the address of the first vararg value... + TmpReg1 = getReg(CI); + addFrameReference(BuildMI(BB, PPC::ADDI, 2, TmpReg1), VarArgsFrameIndex, + 0, false); + return; + + case Intrinsic::vacopy: + TmpReg1 = getReg(CI); + TmpReg2 = getReg(CI.getOperand(1)); + BuildMI(BB, PPC::OR, 2, TmpReg1).addReg(TmpReg2).addReg(TmpReg2); + return; + case Intrinsic::vaend: return; + + case Intrinsic::returnaddress: + TmpReg1 = getReg(CI); + if (cast(CI.getOperand(1))->isNullValue()) { + MachineFrameInfo *MFI = F->getFrameInfo(); + unsigned NumBytes = MFI->getStackSize(); + + BuildMI(BB, PPC::LWZ, 2, TmpReg1).addSImm(NumBytes+8) + .addReg(PPC::R1); + } else { + // Values other than zero are not implemented yet. + BuildMI(BB, PPC::LI, 1, TmpReg1).addSImm(0); + } + return; + + case Intrinsic::frameaddress: + TmpReg1 = getReg(CI); + if (cast(CI.getOperand(1))->isNullValue()) { + BuildMI(BB, PPC::OR, 2, TmpReg1).addReg(PPC::R1).addReg(PPC::R1); + } else { + // Values other than zero are not implemented yet. + BuildMI(BB, PPC::LI, 1, TmpReg1).addSImm(0); + } + return; + + #if 0 + // This may be useful for supporting isunordered + case Intrinsic::isnan: + // If this is only used by 'isunordered' style comparisons, don't emit it. + if (isOnlyUsedByUnorderedComparisons(&CI)) return; + TmpReg1 = getReg(CI.getOperand(1)); + emitUCOM(BB, BB->end(), TmpReg1, TmpReg1); + TmpReg2 = makeAnotherReg(Type::IntTy); + BuildMI(BB, PPC::MFCR, TmpReg2); + TmpReg3 = getReg(CI); + BuildMI(BB, PPC::RLWINM, 4, TmpReg3).addReg(TmpReg2).addImm(4).addImm(31).addImm(31); + return; + #endif + + default: assert(0 && "Error: unknown intrinsics should have been lowered!"); + } + } + + /// 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(); + Value *Op0 = B.getOperand(0), *Op1 = B.getOperand(1); + unsigned Class = getClassB(B.getType()); + + emitSimpleBinaryOperation(BB, MI, Op0, Op1, OperatorClass, DestReg); + } + + /// emitBinaryFPOperation - This method handles emission of floating point + /// Add (0), Sub (1), Mul (2), and Div (3) operations. + void ISel::emitBinaryFPOperation(MachineBasicBlock *BB, + MachineBasicBlock::iterator IP, + Value *Op0, Value *Op1, + unsigned OperatorClass, unsigned DestReg) { + + // Special case: op Reg, + if (ConstantFP *Op1C = dyn_cast(Op1)) { + // Create a constant pool entry for this constant. + MachineConstantPool *CP = F->getConstantPool(); + unsigned CPI = CP->getConstantPoolIndex(Op1C); + const Type *Ty = Op1->getType(); + assert(Ty == Type::FloatTy || Ty == Type::DoubleTy && "Unknown FP type!"); + + static const unsigned OpcodeTab[][4] = { + { PPC::FADDS, PPC::FSUBS, PPC::FMULS, PPC::FDIVS }, // Float + { PPC::FADD, PPC::FSUB, PPC::FMUL, PPC::FDIV }, // Double + }; + + unsigned Opcode = OpcodeTab[Ty != Type::FloatTy][OperatorClass]; + unsigned Op1Reg = getReg(Op1C, BB, IP); + unsigned Op0r = getReg(Op0, BB, IP); + BuildMI(*BB, IP, Opcode, 2, DestReg).addReg(Op0r).addReg(Op1Reg); + return; + } + + // Special case: R1 = op , R2 + if (ConstantFP *Op0C = dyn_cast(Op0)) + if (Op0C->isExactlyValue(-0.0) && OperatorClass == 1) { + // -0.0 - X === -X + unsigned op1Reg = getReg(Op1, BB, IP); + BuildMI(*BB, IP, PPC::FNEG, 1, DestReg).addReg(op1Reg); + return; + } else { + // R1 = op CST, R2 --> R1 = opr R2, CST + + // Create a constant pool entry for this constant. + MachineConstantPool *CP = F->getConstantPool(); + unsigned CPI = CP->getConstantPoolIndex(Op0C); + const Type *Ty = Op0C->getType(); + assert(Ty == Type::FloatTy || Ty == Type::DoubleTy && "Unknown FP type!"); + + static const unsigned OpcodeTab[][4] = { + { PPC::FADDS, PPC::FSUBS, PPC::FMULS, PPC::FDIVS }, // Float + { PPC::FADD, PPC::FSUB, PPC::FMUL, PPC::FDIV }, // Double + }; + + unsigned Opcode = OpcodeTab[Ty != Type::FloatTy][OperatorClass]; + unsigned Op0Reg = getReg(Op0C, BB, IP); + unsigned Op1Reg = getReg(Op1, BB, IP); + BuildMI(*BB, IP, Opcode, 2, DestReg).addReg(Op0Reg).addReg(Op1Reg); + return; + } + + // General case. + static const unsigned OpcodeTab[] = { + PPC::FADD, PPC::FSUB, PPC::FMUL, PPC::FDIV + }; + + unsigned Opcode = OpcodeTab[OperatorClass]; + unsigned Op0r = getReg(Op0, BB, IP); + unsigned Op1r = getReg(Op1, BB, IP); + BuildMI(*BB, IP, Opcode, 2, DestReg).addReg(Op0r).addReg(Op1r); + } + + /// emitSimpleBinaryOperation - 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. + /// + /// emitSimpleBinaryOperation - Common code shared between visitSimpleBinary + /// and constant expression support. + /// + void ISel::emitSimpleBinaryOperation(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Value *Op0, Value *Op1, + unsigned OperatorClass, unsigned DestReg) { + unsigned Class = getClassB(Op0->getType()); + + // Arithmetic and Bitwise operators + static const unsigned OpcodeTab[] = { + PPC::ADD, PPC::SUB, PPC::AND, PPC::OR, PPC::XOR + }; + static const unsigned ImmOpcodeTab[] = { + PPC::ADDI, PPC::SUBI, PPC::ANDIo, PPC::ORI, PPC::XORI + }; + static const unsigned RImmOpcodeTab[] = { + PPC::ADDI, PPC::SUBFIC, PPC::ANDIo, PPC::ORI, PPC::XORI + }; + + if (Class == cFP32 || Class == cFP64) { + assert(OperatorClass < 2 && "No logical ops for FP!"); + emitBinaryFPOperation(MBB, IP, Op0, Op1, OperatorClass, DestReg); + return; + } + + if (Op0->getType() == Type::BoolTy) { + if (OperatorClass == 3) + // If this is an or of two isnan's, emit an FP comparison directly instead + // of or'ing two isnan's together. + if (Value *LHS = dyncastIsNan(Op0)) + if (Value *RHS = dyncastIsNan(Op1)) { + unsigned Op0Reg = getReg(RHS, MBB, IP), Op1Reg = getReg(LHS, MBB, IP); + unsigned TmpReg = makeAnotherReg(Type::IntTy); + emitUCOM(MBB, IP, Op0Reg, Op1Reg); + BuildMI(*MBB, IP, PPC::MFCR, TmpReg); + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(TmpReg).addImm(4) + .addImm(31).addImm(31); + return; + } + } + + // Special case: op , Reg + if (ConstantInt *CI = dyn_cast(Op0)) { + // sub 0, X -> subfic + if (OperatorClass == 1 && canUseAsImmediateForOpcode(CI, 0)) { + unsigned Op1r = getReg(Op1, MBB, IP); + int imm = CI->getRawValue() & 0xFFFF; + BuildMI(*MBB, IP, PPC::SUBFIC, 2, DestReg).addReg(Op1r).addSImm(imm); + return; + } + + // If it is easy to do, swap the operands and emit an immediate op + if (Class != cLong && OperatorClass != 1 && + canUseAsImmediateForOpcode(CI, OperatorClass)) { + unsigned Op1r = getReg(Op1, MBB, IP); + int imm = CI->getRawValue() & 0xFFFF; + + if (OperatorClass < 2) + BuildMI(*MBB, IP, RImmOpcodeTab[OperatorClass], 2, DestReg).addReg(Op1r) + .addSImm(imm); + else + BuildMI(*MBB, IP, RImmOpcodeTab[OperatorClass], 2, DestReg).addReg(Op1r) + .addZImm(imm); + return; + } + } + + // Special case: op Reg, + if (ConstantInt *Op1C = dyn_cast(Op1)) { + unsigned Op0r = getReg(Op0, MBB, IP); + + // xor X, -1 -> not X + if (OperatorClass == 4 && Op1C->isAllOnesValue()) { + BuildMI(*MBB, IP, PPC::NOR, 2, DestReg).addReg(Op0r).addReg(Op0r); + return; + } + + if (canUseAsImmediateForOpcode(Op1C, OperatorClass)) { + int immediate = Op1C->getRawValue() & 0xFFFF; + + if (OperatorClass < 2) + BuildMI(*MBB, IP, ImmOpcodeTab[OperatorClass], 2,DestReg).addReg(Op0r) + .addSImm(immediate); + else + BuildMI(*MBB, IP, ImmOpcodeTab[OperatorClass], 2,DestReg).addReg(Op0r) + .addZImm(immediate); + } else { + unsigned Op1r = getReg(Op1, MBB, IP); + BuildMI(*MBB, IP, OpcodeTab[OperatorClass], 2, DestReg).addReg(Op0r) + .addReg(Op1r); + } + return; + } + + // We couldn't generate an immediate variant of the op, load both halves into + // registers and emit the appropriate opcode. + unsigned Op0r = getReg(Op0, MBB, IP); + unsigned Op1r = getReg(Op1, MBB, IP); + + unsigned Opcode = OpcodeTab[OperatorClass]; + BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(Op0r).addReg(Op1r); + return; + } + + // ExactLog2 - This function solves for (Val == 1 << (N-1)) and returns N. It + // returns zero when the input is not exactly a power of two. + static unsigned ExactLog2(unsigned Val) { + if (Val == 0 || (Val & (Val-1))) return 0; + unsigned Count = 0; + while (Val != 1) { + Val >>= 1; + ++Count; + } + return Count; + } + + /// doMultiply - Emit appropriate instructions to multiply together the + /// Values Op0 and Op1, and put the result in DestReg. + /// + void ISel::doMultiply(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + unsigned DestReg, Value *Op0, Value *Op1) { + unsigned Class0 = getClass(Op0->getType()); + unsigned Class1 = getClass(Op1->getType()); + + unsigned Op0r = getReg(Op0, MBB, IP); + unsigned Op1r = getReg(Op1, MBB, IP); + + // 64 x 64 -> 64 + if (Class0 == cLong && Class1 == cLong) { + unsigned Tmp1 = makeAnotherReg(Type::IntTy); + unsigned Tmp2 = makeAnotherReg(Type::IntTy); + unsigned Tmp3 = makeAnotherReg(Type::IntTy); + unsigned Tmp4 = makeAnotherReg(Type::IntTy); + // FIXME: long is not split into two regs + BuildMI(*MBB, IP, PPC::MULHWU, 2, Tmp1).addReg(Op0r+1).addReg(Op1r+1); + BuildMI(*MBB, IP, PPC::MULLW, 2, DestReg+1).addReg(Op0r+1).addReg(Op1r+1); + BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp2).addReg(Op0r+1).addReg(Op1r); + BuildMI(*MBB, IP, PPC::ADD, 2, Tmp3).addReg(Tmp1).addReg(Tmp2); + BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp4).addReg(Op0r).addReg(Op1r+1); + BuildMI(*MBB, IP, PPC::ADD, 2, DestReg).addReg(Tmp3).addReg(Tmp4); + return; + } + + // 64 x 32 or less, promote 32 to 64 and do a 64 x 64 + if (Class0 == cLong && Class1 <= cInt) { + unsigned Tmp0 = makeAnotherReg(Type::IntTy); + unsigned Tmp1 = makeAnotherReg(Type::IntTy); + unsigned Tmp2 = makeAnotherReg(Type::IntTy); + unsigned Tmp3 = makeAnotherReg(Type::IntTy); + unsigned Tmp4 = makeAnotherReg(Type::IntTy); + if (Op1->getType()->isSigned()) + BuildMI(*MBB, IP, PPC::SRAWI, 2, Tmp0).addReg(Op1r).addImm(31); + else + BuildMI(*MBB, IP, PPC::LI, 2, Tmp0).addSImm(0); + // FIXME: long is not split into two regs + BuildMI(*MBB, IP, PPC::MULHWU, 2, Tmp1).addReg(Op0r+1).addReg(Op1r); + BuildMI(*MBB, IP, PPC::MULLW, 2, DestReg+1).addReg(Op0r+1).addReg(Op1r); + BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp2).addReg(Op0r+1).addReg(Tmp0); + BuildMI(*MBB, IP, PPC::ADD, 2, Tmp3).addReg(Tmp1).addReg(Tmp2); + BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp4).addReg(Op0r).addReg(Op1r); + BuildMI(*MBB, IP, PPC::ADD, 2, DestReg).addReg(Tmp3).addReg(Tmp4); + return; + } + + // 32 x 32 -> 32 + if (Class0 <= cInt && Class1 <= cInt) { + BuildMI(*MBB, IP, PPC::MULLW, 2, DestReg).addReg(Op0r).addReg(Op1r); + return; + } + + assert(0 && "doMultiply cannot operate on unknown type!"); + } + + /// doMultiplyConst - This method will multiply the value in Op0 by the + /// value of the ContantInt *CI + void ISel::doMultiplyConst(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + unsigned DestReg, Value *Op0, ConstantInt *CI) { + unsigned Class = getClass(Op0->getType()); + + // Mul op0, 0 ==> 0 + if (CI->isNullValue()) { + BuildMI(*MBB, IP, PPC::LI, 1, DestReg).addSImm(0); + return; + } + + // Mul op0, 1 ==> op0 + if (CI->equalsInt(1)) { + unsigned Op0r = getReg(Op0, MBB, IP); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(Op0r).addReg(Op0r); + return; + } + + // If the element size is exactly a power of 2, use a shift to get it. + if (unsigned Shift = ExactLog2(CI->getRawValue())) { + ConstantUInt *ShiftCI = ConstantUInt::get(Type::UByteTy, Shift); + emitShiftOperation(MBB, IP, Op0, ShiftCI, true, Op0->getType(), DestReg); + return; + } + + // If 32 bits or less and immediate is in right range, emit mul by immediate + if (Class == cByte || Class == cShort || Class == cInt) { + if (canUseAsImmediateForOpcode(CI, 0)) { + unsigned Op0r = getReg(Op0, MBB, IP); + unsigned imm = CI->getRawValue() & 0xFFFF; + BuildMI(*MBB, IP, PPC::MULLI, 2, DestReg).addReg(Op0r).addSImm(imm); + return; + } + } + + doMultiply(MBB, IP, DestReg, Op0, CI); + } + + void ISel::visitMul(BinaryOperator &I) { + unsigned ResultReg = getReg(I); + + Value *Op0 = I.getOperand(0); + Value *Op1 = I.getOperand(1); + + MachineBasicBlock::iterator IP = BB->end(); + emitMultiply(BB, IP, Op0, Op1, ResultReg); + } + + void ISel::emitMultiply(MachineBasicBlock *MBB, MachineBasicBlock::iterator IP, + Value *Op0, Value *Op1, unsigned DestReg) { + TypeClass Class = getClass(Op0->getType()); + + switch (Class) { + case cByte: + case cShort: + case cInt: + case cLong: + if (ConstantInt *CI = dyn_cast(Op1)) { + doMultiplyConst(MBB, IP, DestReg, Op0, CI); + } else { + doMultiply(MBB, IP, DestReg, Op0, Op1); + } + return; + case cFP32: + case cFP64: + emitBinaryFPOperation(MBB, IP, Op0, Op1, 2, DestReg); + return; + break; + } + } + + + /// visitDivRem - Handle division and remainder instructions... these + /// instruction both require the same instructions to be generated, they just + /// select the result from a different register. Note that both of these + /// instructions work differently for signed and unsigned operands. + /// + void ISel::visitDivRem(BinaryOperator &I) { + unsigned ResultReg = getReg(I); + Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); + + MachineBasicBlock::iterator IP = BB->end(); + emitDivRemOperation(BB, IP, Op0, Op1, I.getOpcode() == Instruction::Div, + ResultReg); + } + + void ISel::emitDivRemOperation(MachineBasicBlock *BB, + MachineBasicBlock::iterator IP, + Value *Op0, Value *Op1, bool isDiv, + unsigned ResultReg) { + const Type *Ty = Op0->getType(); + unsigned Class = getClass(Ty); + switch (Class) { + case cFP32: + if (isDiv) { + // Floating point divide... + emitBinaryFPOperation(BB, IP, Op0, Op1, 3, ResultReg); + return; + } else { + // Floating point remainder via fmodf(float x, float y); + unsigned Op0Reg = getReg(Op0, BB, IP); + unsigned Op1Reg = getReg(Op1, BB, IP); + MachineInstr *TheCall = + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(fmodfFn, true); + std::vector Args; + Args.push_back(ValueRecord(Op0Reg, Type::FloatTy)); + Args.push_back(ValueRecord(Op1Reg, Type::FloatTy)); + doCall(ValueRecord(ResultReg, Type::FloatTy), TheCall, Args, false); + TM.CalledFunctions.insert(fmodfFn); + } + return; + case cFP64: + if (isDiv) { + // Floating point divide... + emitBinaryFPOperation(BB, IP, Op0, Op1, 3, ResultReg); + return; + } else { + // Floating point remainder via fmod(double x, double y); + unsigned Op0Reg = getReg(Op0, BB, IP); + unsigned Op1Reg = getReg(Op1, BB, IP); + MachineInstr *TheCall = + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(fmodFn, true); + std::vector Args; + Args.push_back(ValueRecord(Op0Reg, Type::DoubleTy)); + Args.push_back(ValueRecord(Op1Reg, Type::DoubleTy)); + doCall(ValueRecord(ResultReg, Type::DoubleTy), TheCall, Args, false); + TM.CalledFunctions.insert(fmodFn); + } + return; + case cLong: { + static Function* const Funcs[] = + { __moddi3Fn, __divdi3Fn, __umoddi3Fn, __udivdi3Fn }; + unsigned Op0Reg = getReg(Op0, BB, IP); + unsigned Op1Reg = getReg(Op1, BB, IP); + unsigned NameIdx = Ty->isUnsigned()*2 + isDiv; + MachineInstr *TheCall = + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(Funcs[NameIdx], true); + + std::vector Args; + Args.push_back(ValueRecord(Op0Reg, Type::LongTy)); + Args.push_back(ValueRecord(Op1Reg, Type::LongTy)); + doCall(ValueRecord(ResultReg, Type::LongTy), TheCall, Args, false); + TM.CalledFunctions.insert(Funcs[NameIdx]); + return; + } + case cByte: case cShort: case cInt: + break; // Small integrals, handled below... + default: assert(0 && "Unknown class!"); + } + + // Special case signed division by power of 2. + if (isDiv) + if (ConstantSInt *CI = dyn_cast(Op1)) { + assert(Class != cLong && "This doesn't handle 64-bit divides!"); + int V = CI->getValue(); + + if (V == 1) { // X /s 1 => X + unsigned Op0Reg = getReg(Op0, BB, IP); + BuildMI(*BB, IP, PPC::OR, 2, ResultReg).addReg(Op0Reg).addReg(Op0Reg); + return; + } + + if (V == -1) { // X /s -1 => -X + unsigned Op0Reg = getReg(Op0, BB, IP); + BuildMI(*BB, IP, PPC::NEG, 1, ResultReg).addReg(Op0Reg); + return; + } + + unsigned log2V = ExactLog2(V); + if (log2V != 0 && Ty->isSigned()) { + unsigned Op0Reg = getReg(Op0, BB, IP); + unsigned TmpReg = makeAnotherReg(Op0->getType()); + + BuildMI(*BB, IP, PPC::SRAWI, 2, TmpReg).addReg(Op0Reg).addImm(log2V); + BuildMI(*BB, IP, PPC::ADDZE, 1, ResultReg).addReg(TmpReg); + return; + } + } + + unsigned Op0Reg = getReg(Op0, BB, IP); + unsigned Op1Reg = getReg(Op1, BB, IP); + unsigned Opcode = Ty->isSigned() ? PPC::DIVW : PPC::DIVWU; + + if (isDiv) { + BuildMI(*BB, IP, Opcode, 2, ResultReg).addReg(Op0Reg).addReg(Op1Reg); + } else { // Remainder + unsigned TmpReg1 = makeAnotherReg(Op0->getType()); + unsigned TmpReg2 = makeAnotherReg(Op0->getType()); + + BuildMI(*BB, IP, Opcode, 2, TmpReg1).addReg(Op0Reg).addReg(Op1Reg); + BuildMI(*BB, IP, PPC::MULLW, 2, TmpReg2).addReg(TmpReg1).addReg(Op1Reg); + BuildMI(*BB, IP, PPC::SUBF, 2, ResultReg).addReg(TmpReg2).addReg(Op0Reg); + } + } + + + /// Shift instructions: 'shl', 'sar', 'shr' - Some special cases here + /// for constant immediate shift values, and for constant immediate + /// shift values equal to 1. Even the general case is sort of special, + /// because the shift amount has to be in CL, not just any old register. + /// + void ISel::visitShiftInst(ShiftInst &I) { + MachineBasicBlock::iterator IP = BB->end(); + emitShiftOperation(BB, IP, I.getOperand(0), I.getOperand(1), + I.getOpcode() == Instruction::Shl, I.getType(), + getReg(I)); + } + + /// emitShiftOperation - Common code shared between visitShiftInst and + /// constant expression support. + /// + void ISel::emitShiftOperation(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Value *Op, Value *ShiftAmount, bool isLeftShift, + const Type *ResultTy, unsigned DestReg) { + unsigned SrcReg = getReg (Op, MBB, IP); + bool isSigned = ResultTy->isSigned (); + unsigned Class = getClass (ResultTy); + + // Longs, as usual, are handled specially... + if (Class == cLong) { + // If we have a constant shift, we can generate much more efficient code + // than otherwise... + // + if (ConstantUInt *CUI = dyn_cast(ShiftAmount)) { + unsigned Amount = CUI->getValue(); + if (Amount < 32) { + if (isLeftShift) { + // FIXME: RLWIMI is a use-and-def of DestReg+1, but that violates SSA + // FIXME: long + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) + .addImm(Amount).addImm(0).addImm(31-Amount); + BuildMI(*MBB, IP, PPC::RLWIMI, 5).addReg(DestReg).addReg(SrcReg+1) + .addImm(Amount).addImm(32-Amount).addImm(31); + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg+1).addReg(SrcReg+1) + .addImm(Amount).addImm(0).addImm(31-Amount); + } else { + // FIXME: RLWIMI is a use-and-def of DestReg, but that violates SSA + // FIXME: long + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg+1).addReg(SrcReg+1) + .addImm(32-Amount).addImm(Amount).addImm(31); + BuildMI(*MBB, IP, PPC::RLWIMI, 5).addReg(DestReg+1).addReg(SrcReg) + .addImm(32-Amount).addImm(0).addImm(Amount-1); + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) + .addImm(32-Amount).addImm(Amount).addImm(31); + } + } else { // Shifting more than 32 bits + Amount -= 32; + if (isLeftShift) { + if (Amount != 0) { + // FIXME: long + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg+1) + .addImm(Amount).addImm(0).addImm(31-Amount); + } else { + // FIXME: long + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg+1) + .addReg(SrcReg+1); + } + BuildMI(*MBB, IP, PPC::LI, 1, DestReg+1).addSImm(0); + } else { + if (Amount != 0) { + if (isSigned) + BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg+1).addReg(SrcReg) + .addImm(Amount); + else + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg+1).addReg(SrcReg) + .addImm(32-Amount).addImm(Amount).addImm(31); + } else { + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) + .addReg(SrcReg); + } + BuildMI(*MBB, IP,PPC::LI, 1, DestReg).addSImm(0); + } + } + } else { + unsigned TmpReg1 = makeAnotherReg(Type::IntTy); + unsigned TmpReg2 = makeAnotherReg(Type::IntTy); + unsigned TmpReg3 = makeAnotherReg(Type::IntTy); + unsigned TmpReg4 = makeAnotherReg(Type::IntTy); + unsigned TmpReg5 = makeAnotherReg(Type::IntTy); + unsigned TmpReg6 = makeAnotherReg(Type::IntTy); + unsigned ShiftAmountReg = getReg (ShiftAmount, MBB, IP); + + if (isLeftShift) { + BuildMI(*MBB, IP, PPC::SUBFIC, 2, TmpReg1).addReg(ShiftAmountReg) + .addSImm(32); + BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg2).addReg(SrcReg) + .addReg(ShiftAmountReg); + BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg3).addReg(SrcReg+1) + .addReg(TmpReg1); + BuildMI(*MBB, IP, PPC::OR, 2,TmpReg4).addReg(TmpReg2).addReg(TmpReg3); + BuildMI(*MBB, IP, PPC::ADDI, 2, TmpReg5).addReg(ShiftAmountReg) + .addSImm(-32); + BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg6).addReg(SrcReg+1) + .addReg(TmpReg5); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(TmpReg4) + .addReg(TmpReg6); + BuildMI(*MBB, IP, PPC::SLW, 2, DestReg+1).addReg(SrcReg+1) + .addReg(ShiftAmountReg); + } else { + if (isSigned) { + // FIXME: Unimplemented + // Page C-3 of the PowerPC 32bit Programming Environments Manual + std::cerr << "ERROR: Unimplemented: signed right shift of long\n"; + abort(); + } else { + BuildMI(*MBB, IP, PPC::SUBFIC, 2, TmpReg1).addReg(ShiftAmountReg) + .addSImm(32); + BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg2).addReg(SrcReg+1) + .addReg(ShiftAmountReg); + BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg3).addReg(SrcReg) + .addReg(TmpReg1); + BuildMI(*MBB, IP, PPC::OR, 2, TmpReg4).addReg(TmpReg2) + .addReg(TmpReg3); + BuildMI(*MBB, IP, PPC::ADDI, 2, TmpReg5).addReg(ShiftAmountReg) + .addSImm(-32); + BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg6).addReg(SrcReg) + .addReg(TmpReg5); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(TmpReg4) + .addReg(TmpReg6); + BuildMI(*MBB, IP, PPC::SRW, 2, DestReg).addReg(SrcReg) + .addReg(ShiftAmountReg); + } + } + } + return; + } + + if (ConstantUInt *CUI = dyn_cast(ShiftAmount)) { + // The shift amount is constant, guaranteed to be a ubyte. Get its value. + assert(CUI->getType() == Type::UByteTy && "Shift amount not a ubyte?"); + unsigned Amount = CUI->getValue(); + + if (isLeftShift) { + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) + .addImm(Amount).addImm(0).addImm(31-Amount); + } else { + if (isSigned) { + BuildMI(*MBB, IP, PPC::SRAWI,2,DestReg).addReg(SrcReg).addImm(Amount); + } else { + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) + .addImm(32-Amount).addImm(Amount).addImm(31); + } + } + } else { // The shift amount is non-constant. + unsigned ShiftAmountReg = getReg (ShiftAmount, MBB, IP); + + if (isLeftShift) { + BuildMI(*MBB, IP, PPC::SLW, 2, DestReg).addReg(SrcReg) + .addReg(ShiftAmountReg); + } else { + BuildMI(*MBB, IP, isSigned ? PPC::SRAW : PPC::SRW, 2, DestReg) + .addReg(SrcReg).addReg(ShiftAmountReg); + } + } + } + + + /// visitLoadInst - Implement LLVM load instructions. Pretty straightforward + /// mapping of LLVM classes to PPC load instructions, with the exception of + /// signed byte loads, which need a sign extension following them. + /// + void ISel::visitLoadInst(LoadInst &I) { + // Immediate opcodes, for reg+imm addressing + static const unsigned ImmOpcodes[] = { + PPC::LBZ, PPC::LHZ, PPC::LWZ, + PPC::LFS, PPC::LFD, PPC::LWZ + }; + // Indexed opcodes, for reg+reg addressing + static const unsigned IdxOpcodes[] = { + PPC::LBZX, PPC::LHZX, PPC::LWZX, + PPC::LFSX, PPC::LFDX, PPC::LWZX + }; + + unsigned Class = getClassB(I.getType()); + unsigned ImmOpcode = ImmOpcodes[Class]; + unsigned IdxOpcode = IdxOpcodes[Class]; + unsigned DestReg = getReg(I); + Value *SourceAddr = I.getOperand(0); + + if (Class == cShort && I.getType()->isSigned()) ImmOpcode = PPC::LHA; + if (Class == cShort && I.getType()->isSigned()) IdxOpcode = PPC::LHAX; + + if (AllocaInst *AI = dyn_castFixedAlloca(SourceAddr)) { + unsigned FI = getFixedSizedAllocaFI(AI); + if (Class == cByte && I.getType()->isSigned()) { + unsigned TmpReg = makeAnotherReg(I.getType()); + addFrameReference(BuildMI(BB, ImmOpcode, 2, TmpReg), FI); + BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg); + } else { + addFrameReference(BuildMI(BB, ImmOpcode, 2, DestReg), FI); + } + return; + } + + // If this load is the only use of the GEP instruction that is its address, + // then we can fold the GEP directly into the load instruction. + // emitGEPOperation with a second to last arg of 'true' will place the + // base register for the GEP into baseReg, and the constant offset from that + // into offset. If the offset fits in 16 bits, we can emit a reg+imm store + // otherwise, we copy the offset into another reg, and use reg+reg addressing. + if (GetElementPtrInst *GEPI = canFoldGEPIntoLoadOrStore(SourceAddr)) { + unsigned baseReg = getReg(GEPI); + unsigned pendingAdd; + ConstantSInt *offset; + + emitGEPOperation(BB, BB->end(), GEPI->getOperand(0), GEPI->op_begin()+1, + GEPI->op_end(), baseReg, true, &offset, &pendingAdd); + + if (pendingAdd == 0 && Class != cLong && + canUseAsImmediateForOpcode(offset, 0)) { + if (Class == cByte && I.getType()->isSigned()) { + unsigned TmpReg = makeAnotherReg(I.getType()); + BuildMI(BB, ImmOpcode, 2, TmpReg).addSImm(offset->getValue()) + .addReg(baseReg); + BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg); + } else { + BuildMI(BB, ImmOpcode, 2, DestReg).addSImm(offset->getValue()) + .addReg(baseReg); + } + return; + } + + unsigned indexReg = (pendingAdd != 0) ? pendingAdd : getReg(offset); + + if (Class == cByte && I.getType()->isSigned()) { + unsigned TmpReg = makeAnotherReg(I.getType()); + BuildMI(BB, IdxOpcode, 2, TmpReg).addReg(indexReg).addReg(baseReg); + BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg); + } else { + BuildMI(BB, IdxOpcode, 2, DestReg).addReg(indexReg).addReg(baseReg); + } + return; + } + + // The fallback case, where the load was from a source that could not be + // folded into the load instruction. + unsigned SrcAddrReg = getReg(SourceAddr); + + if (Class == cByte && I.getType()->isSigned()) { + unsigned TmpReg = makeAnotherReg(I.getType()); + BuildMI(BB, ImmOpcode, 2, TmpReg).addSImm(0).addReg(SrcAddrReg); + BuildMI(BB, PPC::EXTSB, 1, DestReg).addReg(TmpReg); + } else { + BuildMI(BB, ImmOpcode, 2, DestReg).addSImm(0).addReg(SrcAddrReg); + } + } + + /// visitStoreInst - Implement LLVM store instructions + /// + void ISel::visitStoreInst(StoreInst &I) { + // Immediate opcodes, for reg+imm addressing + static const unsigned ImmOpcodes[] = { + PPC::STB, PPC::STH, PPC::STW, + PPC::STFS, PPC::STFD, PPC::STW + }; + // Indexed opcodes, for reg+reg addressing + static const unsigned IdxOpcodes[] = { + PPC::STBX, PPC::STHX, PPC::STWX, + PPC::STFSX, PPC::STFDX, PPC::STWX + }; + + Value *SourceAddr = I.getOperand(1); + const Type *ValTy = I.getOperand(0)->getType(); + unsigned Class = getClassB(ValTy); + unsigned ImmOpcode = ImmOpcodes[Class]; + unsigned IdxOpcode = IdxOpcodes[Class]; + unsigned ValReg = getReg(I.getOperand(0)); + + // If this store is the only use of the GEP instruction that is its address, + // then we can fold the GEP directly into the store instruction. + // emitGEPOperation with a second to last arg of 'true' will place the + // base register for the GEP into baseReg, and the constant offset from that + // into offset. If the offset fits in 16 bits, we can emit a reg+imm store + // otherwise, we copy the offset into another reg, and use reg+reg addressing. + if (GetElementPtrInst *GEPI = canFoldGEPIntoLoadOrStore(SourceAddr)) { + unsigned baseReg = getReg(GEPI); + unsigned pendingAdd; + ConstantSInt *offset; + + emitGEPOperation(BB, BB->end(), GEPI->getOperand(0), GEPI->op_begin()+1, + GEPI->op_end(), baseReg, true, &offset, &pendingAdd); + + if (0 == pendingAdd && Class != cLong && + canUseAsImmediateForOpcode(offset, 0)) { + BuildMI(BB, ImmOpcode, 3).addReg(ValReg).addSImm(offset->getValue()) + .addReg(baseReg); + return; + } + + unsigned indexReg = (pendingAdd != 0) ? pendingAdd : getReg(offset); + BuildMI(BB, IdxOpcode, 3).addReg(ValReg).addReg(indexReg).addReg(baseReg); + return; + } + + // If the store address wasn't the only use of a GEP, we fall back to the + // standard path: store the ValReg at the value in AddressReg. + unsigned AddressReg = getReg(I.getOperand(1)); + BuildMI(BB, ImmOpcode, 3).addReg(ValReg).addSImm(0).addReg(AddressReg); + } + + + /// 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); + + unsigned SrcClass = getClassB(Op->getType()); + unsigned DestClass = getClassB(CI.getType()); + + // If this is a cast from a 32-bit integer to a Long type, and the only uses + // of the case are GEP instructions, then the cast does not need to be + // generated explicitly, it will be folded into the GEP. + if (DestClass == cLong && SrcClass == cInt) { + bool AllUsesAreGEPs = true; + for (Value::use_iterator I = CI.use_begin(), E = CI.use_end(); I != E; ++I) + if (!isa(*I)) { + AllUsesAreGEPs = false; + break; + } + + // No need to codegen this cast if all users are getelementptr instrs... + if (AllUsesAreGEPs) return; + } + + unsigned DestReg = getReg(CI); + MachineBasicBlock::iterator MI = BB->end(); + emitCastOperation(BB, MI, Op, CI.getType(), DestReg); + } + + /// emitCastOperation - Common code shared between visitCastInst and constant + /// expression cast support. + /// + void ISel::emitCastOperation(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Value *Src, const Type *DestTy, + unsigned DestReg) { + const Type *SrcTy = Src->getType(); + unsigned SrcClass = getClassB(SrcTy); + unsigned DestClass = getClassB(DestTy); + unsigned SrcReg = getReg(Src, MBB, IP); + + // Implement casts to bool by using compare on the operand followed by set if + // not zero on the result. + if (DestTy == Type::BoolTy) { + switch (SrcClass) { + case cByte: + case cShort: + case cInt: + case cLong: { + unsigned TmpReg = makeAnotherReg(Type::IntTy); + BuildMI(*MBB, IP, PPC::ADDIC, 2, TmpReg).addReg(SrcReg).addSImm(-1); + BuildMI(*MBB, IP, PPC::SUBFE, 2, DestReg).addReg(TmpReg).addReg(SrcReg); + break; + } + case cFP32: + case cFP64: + // FSEL perhaps? + std::cerr << "ERROR: Cast fp-to-bool not implemented!\n"; + abort(); + } + return; + } + + // Handle cast of Float -> Double + if (SrcClass == cFP32 && DestClass == cFP64) { + BuildMI(*MBB, IP, PPC::FMR, 1, DestReg).addReg(SrcReg); + return; + } + + // Handle cast of Double -> Float + if (SrcClass == cFP64 && DestClass == cFP32) { + BuildMI(*MBB, IP, PPC::FRSP, 1, DestReg).addReg(SrcReg); + return; + } + + // Handle casts from integer to floating point now... + if (DestClass == cFP32 || DestClass == cFP64) { + + // Emit a library call for long to float conversion + if (SrcClass == cLong) { + std::vector Args; + Args.push_back(ValueRecord(SrcReg, SrcTy)); + Function *floatFn = (DestClass == cFP32) ? __floatdisfFn : __floatdidfFn; + MachineInstr *TheCall = + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(floatFn, true); + doCall(ValueRecord(DestReg, DestTy), TheCall, Args, false); + TM.CalledFunctions.insert(floatFn); + return; + } + + // Make sure we're dealing with a full 32 bits + unsigned TmpReg = makeAnotherReg(Type::IntTy); + promote32(TmpReg, ValueRecord(SrcReg, SrcTy)); + + SrcReg = TmpReg; + + // Spill the integer to memory and reload it from there. + // Also spill room for a special conversion constant + int ConstantFrameIndex = + F->getFrameInfo()->CreateStackObject(Type::DoubleTy, TM.getTargetData()); + int ValueFrameIdx = + F->getFrameInfo()->CreateStackObject(Type::DoubleTy, TM.getTargetData()); + + unsigned constantHi = makeAnotherReg(Type::IntTy); + unsigned constantLo = makeAnotherReg(Type::IntTy); + unsigned ConstF = makeAnotherReg(Type::DoubleTy); + unsigned TempF = makeAnotherReg(Type::DoubleTy); + + if (!SrcTy->isSigned()) { + BuildMI(*BB, IP, PPC::LIS, 1, constantHi).addSImm(0x4330); + BuildMI(*BB, IP, PPC::LI, 1, constantLo).addSImm(0); + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(constantHi), + ConstantFrameIndex); + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(constantLo), + ConstantFrameIndex, 4); + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(constantHi), + ValueFrameIdx); + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(SrcReg), + ValueFrameIdx, 4); + addFrameReference(BuildMI(*BB, IP, PPC::LFD, 2, ConstF), + ConstantFrameIndex); + addFrameReference(BuildMI(*BB, IP, PPC::LFD, 2, TempF), ValueFrameIdx); + BuildMI(*BB, IP, PPC::FSUB, 2, DestReg).addReg(TempF).addReg(ConstF); + } else { + unsigned TempLo = makeAnotherReg(Type::IntTy); + BuildMI(*BB, IP, PPC::LIS, 1, constantHi).addSImm(0x4330); + BuildMI(*BB, IP, PPC::LIS, 1, constantLo).addSImm(0x8000); + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(constantHi), + ConstantFrameIndex); + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(constantLo), + ConstantFrameIndex, 4); + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(constantHi), + ValueFrameIdx); + BuildMI(*BB, IP, PPC::XORIS, 2, TempLo).addReg(SrcReg).addImm(0x8000); + addFrameReference(BuildMI(*BB, IP, PPC::STW, 3).addReg(TempLo), + ValueFrameIdx, 4); + addFrameReference(BuildMI(*BB, IP, PPC::LFD, 2, ConstF), + ConstantFrameIndex); + addFrameReference(BuildMI(*BB, IP, PPC::LFD, 2, TempF), ValueFrameIdx); + BuildMI(*BB, IP, PPC::FSUB, 2, DestReg).addReg(TempF).addReg(ConstF); + } + return; + } + + // Handle casts from floating point to integer now... + if (SrcClass == cFP32 || SrcClass == cFP64) { + static Function* const Funcs[] = + { __fixsfdiFn, __fixdfdiFn, __fixunssfdiFn, __fixunsdfdiFn }; + // emit library call + if (DestClass == cLong) { + bool isDouble = SrcClass == cFP64; + unsigned nameIndex = 2 * DestTy->isSigned() + isDouble; + std::vector Args; + Args.push_back(ValueRecord(SrcReg, SrcTy)); + Function *floatFn = Funcs[nameIndex]; + MachineInstr *TheCall = + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(floatFn, true); + doCall(ValueRecord(DestReg, DestTy), TheCall, Args, false); + TM.CalledFunctions.insert(floatFn); + return; + } + + int ValueFrameIdx = + F->getFrameInfo()->CreateStackObject(SrcTy, TM.getTargetData()); + + if (DestTy->isSigned()) { + unsigned TempReg = makeAnotherReg(Type::DoubleTy); + + // Convert to integer in the FP reg and store it to a stack slot + BuildMI(*BB, IP, PPC::FCTIWZ, 1, TempReg).addReg(SrcReg); + addFrameReference(BuildMI(*BB, IP, PPC::STFD, 3) + .addReg(TempReg), ValueFrameIdx); + + // There is no load signed byte opcode, so we must emit a sign extend for + // that particular size. Make sure to source the new integer from the + // correct offset. + if (DestClass == cByte) { + unsigned TempReg2 = makeAnotherReg(DestTy); + addFrameReference(BuildMI(*BB, IP, PPC::LBZ, 2, TempReg2), + ValueFrameIdx, 7); + BuildMI(*MBB, IP, PPC::EXTSB, DestReg).addReg(TempReg2); + } else { + int offset = (DestClass == cShort) ? 6 : 4; + unsigned LoadOp = (DestClass == cShort) ? PPC::LHA : PPC::LWZ; + addFrameReference(BuildMI(*BB, IP, LoadOp, 2, DestReg), + ValueFrameIdx, offset); + } + } else { + unsigned Zero = getReg(ConstantFP::get(Type::DoubleTy, 0.0f)); + double maxInt = (1LL << 32) - 1; + unsigned MaxInt = getReg(ConstantFP::get(Type::DoubleTy, maxInt)); + double border = 1LL << 31; + unsigned Border = getReg(ConstantFP::get(Type::DoubleTy, border)); + unsigned UseZero = makeAnotherReg(Type::DoubleTy); + unsigned UseMaxInt = makeAnotherReg(Type::DoubleTy); + unsigned UseChoice = makeAnotherReg(Type::DoubleTy); + unsigned TmpReg = makeAnotherReg(Type::DoubleTy); + unsigned TmpReg2 = makeAnotherReg(Type::DoubleTy); + unsigned ConvReg = makeAnotherReg(Type::DoubleTy); + unsigned IntTmp = makeAnotherReg(Type::IntTy); + unsigned XorReg = makeAnotherReg(Type::IntTy); + int FrameIdx = + F->getFrameInfo()->CreateStackObject(SrcTy, TM.getTargetData()); + // Update machine-CFG edges + MachineBasicBlock *XorMBB = new MachineBasicBlock(BB->getBasicBlock()); + MachineBasicBlock *PhiMBB = new MachineBasicBlock(BB->getBasicBlock()); + MachineBasicBlock *OldMBB = BB; + ilist::iterator It = BB; ++It; + F->getBasicBlockList().insert(It, XorMBB); + F->getBasicBlockList().insert(It, PhiMBB); + BB->addSuccessor(XorMBB); + BB->addSuccessor(PhiMBB); + + // Convert from floating point to unsigned 32-bit value + // Use 0 if incoming value is < 0.0 + BuildMI(*BB, IP, PPC::FSEL, 3, UseZero).addReg(SrcReg).addReg(SrcReg) + .addReg(Zero); + // Use 2**32 - 1 if incoming value is >= 2**32 + BuildMI(*BB, IP, PPC::FSUB, 2, UseMaxInt).addReg(MaxInt).addReg(SrcReg); + BuildMI(*BB, IP, PPC::FSEL, 3, UseChoice).addReg(UseMaxInt) + .addReg(UseZero).addReg(MaxInt); + // Subtract 2**31 + BuildMI(*BB, IP, PPC::FSUB, 2, TmpReg).addReg(UseChoice).addReg(Border); + // Use difference if >= 2**31 + BuildMI(*BB, IP, PPC::FCMPU, 2, PPC::CR0).addReg(UseChoice) + .addReg(Border); + BuildMI(*BB, IP, PPC::FSEL, 3, TmpReg2).addReg(TmpReg).addReg(TmpReg) + .addReg(UseChoice); + // Convert to integer + BuildMI(*BB, IP, PPC::FCTIWZ, 1, ConvReg).addReg(TmpReg2); + addFrameReference(BuildMI(*BB, IP, PPC::STFD, 3).addReg(ConvReg), + FrameIdx); + if (DestClass == cByte) { + addFrameReference(BuildMI(*BB, IP, PPC::LBZ, 2, DestReg), + FrameIdx, 7); + } else if (DestClass == cShort) { + addFrameReference(BuildMI(*BB, IP, PPC::LHZ, 2, DestReg), + FrameIdx, 6); + } if (DestClass == cInt) { + addFrameReference(BuildMI(*BB, IP, PPC::LWZ, 2, IntTmp), + FrameIdx, 4); + BuildMI(*BB, IP, PPC::BLT, 2).addReg(PPC::CR0).addMBB(PhiMBB); + BuildMI(*BB, IP, PPC::B, 1).addMBB(XorMBB); + + // XorMBB: + // add 2**31 if input was >= 2**31 + BB = XorMBB; + BuildMI(BB, PPC::XORIS, 2, XorReg).addReg(IntTmp).addImm(0x8000); + XorMBB->addSuccessor(PhiMBB); + + // PhiMBB: + // DestReg = phi [ IntTmp, OldMBB ], [ XorReg, XorMBB ] + BB = PhiMBB; + BuildMI(BB, PPC::PHI, 2, DestReg).addReg(IntTmp).addMBB(OldMBB) + .addReg(XorReg).addMBB(XorMBB); + } + } + return; + } + + // Check our invariants + assert((SrcClass <= cInt || SrcClass == cLong) && + "Unhandled source class for cast operation!"); + assert((DestClass <= cInt || DestClass == cLong) && + "Unhandled destination class for cast operation!"); + + bool sourceUnsigned = SrcTy->isUnsigned() || SrcTy == Type::BoolTy; + bool destUnsigned = DestTy->isUnsigned(); + + // Unsigned -> Unsigned, clear if larger + if (sourceUnsigned && destUnsigned) { + // handle long dest class now to keep switch clean + if (DestClass == cLong) { + // FIXME: long + if (SrcClass == cLong) { + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg+1) + .addReg(SrcReg+1); + } else { + BuildMI(*MBB, IP, PPC::LI, 1, DestReg).addSImm(0); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) + .addReg(SrcReg); + } + return; + } + + // handle u{ byte, short, int } x u{ byte, short, int } + unsigned clearBits = (SrcClass == cByte || DestClass == cByte) ? 24 : 16; + switch (SrcClass) { + case cByte: + case cShort: + if (SrcClass == DestClass) + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + else + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) + .addImm(0).addImm(clearBits).addImm(31); + break; + case cLong: + ++SrcReg; + // Fall through + case cInt: + if (DestClass == cInt) + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + else + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) + .addImm(0).addImm(clearBits).addImm(31); + break; + } + return; + } + + // Signed -> Signed + if (!sourceUnsigned && !destUnsigned) { + // handle long dest class now to keep switch clean + if (DestClass == cLong) { + // FIXME: long + if (SrcClass == cLong) { + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg+1) + .addReg(SrcReg+1); + } else { + BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg).addReg(SrcReg).addImm(31); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) + .addReg(SrcReg); + } + return; + } + + // handle { byte, short, int } x { byte, short, int } + switch (SrcClass) { + case cByte: + if (DestClass == cByte) + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + else + BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg); + break; + case cShort: + if (DestClass == cByte) + BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg); + else if (DestClass == cShort) + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + else + BuildMI(*MBB, IP, PPC::EXTSH, 1, DestReg).addReg(SrcReg); + break; + case cLong: + ++SrcReg; + // Fall through + case cInt: + if (DestClass == cByte) + BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg); + else if (DestClass == cShort) + BuildMI(*MBB, IP, PPC::EXTSH, 1, DestReg).addReg(SrcReg); + else + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + break; + } + return; + } + + // Unsigned -> Signed + if (sourceUnsigned && !destUnsigned) { + // handle long dest class now to keep switch clean + if (DestClass == cLong) { + // FIXME: long + if (SrcClass == cLong) { + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg+1). + addReg(SrcReg+1); + } else { + BuildMI(*MBB, IP, PPC::LI, 1, DestReg).addSImm(0); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) + .addReg(SrcReg); + } + return; + } + + // handle u{ byte, short, int } -> { byte, short, int } + switch (SrcClass) { + case cByte: + if (DestClass == cByte) + // uByte 255 -> signed byte == -1 + BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg); + else + // uByte 255 -> signed short/int == 255 + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg).addImm(0) + .addImm(24).addImm(31); + break; + case cShort: + if (DestClass == cByte) + BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg); + else if (DestClass == cShort) + BuildMI(*MBB, IP, PPC::EXTSH, 1, DestReg).addReg(SrcReg); + else + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg).addImm(0) + .addImm(16).addImm(31); + break; + case cLong: + ++SrcReg; + // Fall through + case cInt: + if (DestClass == cByte) + BuildMI(*MBB, IP, PPC::EXTSB, 1, DestReg).addReg(SrcReg); + else if (DestClass == cShort) + BuildMI(*MBB, IP, PPC::EXTSH, 1, DestReg).addReg(SrcReg); + else + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + break; + } + return; + } + + // Signed -> Unsigned + if (!sourceUnsigned && destUnsigned) { + // handle long dest class now to keep switch clean + if (DestClass == cLong) { + // FIXME: long + if (SrcClass == cLong) { + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg+1) + .addReg(SrcReg+1); + } else { + BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg).addReg(SrcReg).addImm(31); + BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) + .addReg(SrcReg); + } + return; + } + + // handle { byte, short, int } -> u{ byte, short, int } + unsigned clearBits = (DestClass == cByte) ? 24 : 16; + switch (SrcClass) { + case cByte: + case cShort: + if (DestClass == cByte || DestClass == cShort) + // sbyte -1 -> ubyte 0x000000FF + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) + .addImm(0).addImm(clearBits).addImm(31); + else + // sbyte -1 -> ubyte 0xFFFFFFFF + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + break; + case cLong: + ++SrcReg; + // Fall through + case cInt: + if (DestClass == cInt) + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); + else + BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) + .addImm(0).addImm(clearBits).addImm(31); + break; + } + return; + } + + // Anything we haven't handled already, we can't (yet) handle at all. + std::cerr << "Unhandled cast from " << SrcTy->getDescription() + << "to " << DestTy->getDescription() << '\n'; + abort(); + } + + /// visitVANextInst - Implement the va_next instruction... + /// + void ISel::visitVANextInst(VANextInst &I) { + unsigned VAList = getReg(I.getOperand(0)); + unsigned DestReg = getReg(I); + + unsigned Size; + switch (I.getArgType()->getTypeID()) { + default: + std::cerr << I; + assert(0 && "Error: bad type for va_next instruction!"); + return; + case Type::PointerTyID: + case Type::UIntTyID: + case Type::IntTyID: + Size = 4; + break; + case Type::ULongTyID: + case Type::LongTyID: + case Type::DoubleTyID: + Size = 8; + break; + } + + // Increment the VAList pointer... + BuildMI(BB, PPC::ADDI, 2, DestReg).addReg(VAList).addSImm(Size); + } + + void ISel::visitVAArgInst(VAArgInst &I) { + unsigned VAList = getReg(I.getOperand(0)); + unsigned DestReg = getReg(I); + + switch (I.getType()->getTypeID()) { + default: + std::cerr << I; + assert(0 && "Error: bad type for va_next instruction!"); + return; + case Type::PointerTyID: + case Type::UIntTyID: + case Type::IntTyID: + BuildMI(BB, PPC::LWZ, 2, DestReg).addSImm(0).addReg(VAList); + break; + case Type::ULongTyID: + case Type::LongTyID: + BuildMI(BB, PPC::LD, 2, DestReg).addSImm(0).addReg(VAList); + break; + case Type::FloatTyID: + BuildMI(BB, PPC::LFS, 2, DestReg).addSImm(0).addReg(VAList); + break; + case Type::DoubleTyID: + BuildMI(BB, PPC::LFD, 2, DestReg).addSImm(0).addReg(VAList); + break; + } + } + + /// visitGetElementPtrInst - instruction-select GEP instructions + /// + void ISel::visitGetElementPtrInst(GetElementPtrInst &I) { + if (canFoldGEPIntoLoadOrStore(&I)) + return; + + unsigned outputReg = getReg(I); + emitGEPOperation(BB, BB->end(), I.getOperand(0), I.op_begin()+1, I.op_end(), + outputReg, false, 0, 0); + } + + /// emitGEPOperation - Common code shared between visitGetElementPtrInst and + /// constant expression GEP support. + /// + void ISel::emitGEPOperation(MachineBasicBlock *MBB, + MachineBasicBlock::iterator IP, + Value *Src, User::op_iterator IdxBegin, + User::op_iterator IdxEnd, unsigned TargetReg, + bool GEPIsFolded, ConstantSInt **RemainderPtr, + unsigned *PendingAddReg) { + const TargetData &TD = TM.getTargetData(); + const Type *Ty = Src->getType(); + unsigned basePtrReg = getReg(Src, MBB, IP); + int64_t constValue = 0; + + // Record the operations to emit the GEP in a vector so that we can emit them + // after having analyzed the entire instruction. + std::vector ops; + + // 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; + if (const StructType *StTy = dyn_cast(Ty)) { + // It's a struct access. idx is the index into the structure, + // which names the field. Use the TargetData structure to + // pick out what the layout of the structure is in memory. + // Use the (constant) structure index's value to find the + // right byte offset from the StructLayout class's list of + // structure member offsets. + unsigned fieldIndex = cast(idx)->getValue(); + unsigned memberOffset = + TD.getStructLayout(StTy)->MemberOffsets[fieldIndex]; + + // StructType member offsets are always constant values. Add it to the + // running total. + constValue += memberOffset; + + // The next type is the member of the structure selected by the + // index. + Ty = StTy->getElementType (fieldIndex); + } else if (const SequentialType *SqTy = dyn_cast (Ty)) { + // Many GEP instructions use a [cast (int/uint) to LongTy] as their + // operand. Handle this case directly now... + if (CastInst *CI = dyn_cast(idx)) + if (CI->getOperand(0)->getType() == Type::IntTy || + CI->getOperand(0)->getType() == Type::UIntTy) + idx = CI->getOperand(0); + + // It's an array or pointer access: [ArraySize x ElementType]. + // We want to add basePtrReg 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); + + if (ConstantInt *C = dyn_cast(idx)) { + if (ConstantSInt *CS = dyn_cast(C)) + constValue += CS->getValue() * elementSize; + else if (ConstantUInt *CU = dyn_cast(C)) + constValue += CU->getValue() * elementSize; + else + assert(0 && "Invalid ConstantInt GEP index type!"); + } else { + // Push current gep state to this point as an add + ops.push_back(CollapsedGepOp(false, 0, + ConstantSInt::get(Type::IntTy,constValue))); + + // Push multiply gep op and reset constant value + ops.push_back(CollapsedGepOp(true, idx, + ConstantSInt::get(Type::IntTy, elementSize))); + + constValue = 0; + } + } + } + // Emit instructions for all the collapsed ops + bool pendingAdd = false; + unsigned pendingAddReg = 0; + + for(std::vector::iterator cgo_i = ops.begin(), + cgo_e = ops.end(); cgo_i != cgo_e; ++cgo_i) { + CollapsedGepOp& cgo = *cgo_i; + unsigned nextBasePtrReg = makeAnotherReg(Type::IntTy); + + // If we didn't emit an add last time through the loop, we need to now so + // that the base reg is updated appropriately. + if (pendingAdd) { + assert(pendingAddReg != 0 && "Uninitialized register in pending add!"); + BuildMI(*MBB, IP, PPC::ADD, 2, nextBasePtrReg).addReg(basePtrReg) + .addReg(pendingAddReg); + basePtrReg = nextBasePtrReg; + nextBasePtrReg = makeAnotherReg(Type::IntTy); + pendingAddReg = 0; + pendingAdd = false; + } + + if (cgo.isMul) { + // We know the elementSize is a constant, so we can emit a constant mul + unsigned TmpReg = makeAnotherReg(Type::IntTy); + doMultiplyConst(MBB, IP, nextBasePtrReg, cgo.index, cgo.size); + pendingAddReg = basePtrReg; + pendingAdd = true; + } else { + // Try and generate an immediate addition if possible + if (cgo.size->isNullValue()) { + BuildMI(*MBB, IP, PPC::OR, 2, nextBasePtrReg).addReg(basePtrReg) + .addReg(basePtrReg); + } else if (canUseAsImmediateForOpcode(cgo.size, 0)) { + BuildMI(*MBB, IP, PPC::ADDI, 2, nextBasePtrReg).addReg(basePtrReg) + .addSImm(cgo.size->getValue()); + } else { + unsigned Op1r = getReg(cgo.size, MBB, IP); + BuildMI(*MBB, IP, PPC::ADD, 2, nextBasePtrReg).addReg(basePtrReg) + .addReg(Op1r); + } + } + + basePtrReg = nextBasePtrReg; + } + // Add the current base register plus any accumulated constant value + ConstantSInt *remainder = ConstantSInt::get(Type::IntTy, constValue); + + // If we are emitting this during a fold, copy the current base register to + // the target, and save the current constant offset so the folding load or + // store can try and use it as an immediate. + if (GEPIsFolded) { + // If this is a folded GEP and the last element was an index, then we need + // to do some extra work to turn a shift/add/stw into a shift/stwx + if (pendingAdd && 0 == remainder->getValue()) { + assert(pendingAddReg != 0 && "Uninitialized register in pending add!"); + *PendingAddReg = pendingAddReg; + } else { + *PendingAddReg = 0; + if (pendingAdd) { + unsigned nextBasePtrReg = makeAnotherReg(Type::IntTy); + assert(pendingAddReg != 0 && "Uninitialized register in pending add!"); + BuildMI(*MBB, IP, PPC::ADD, 2, nextBasePtrReg).addReg(basePtrReg) + .addReg(pendingAddReg); + basePtrReg = nextBasePtrReg; + } + } + BuildMI (*MBB, IP, PPC::OR, 2, TargetReg).addReg(basePtrReg) + .addReg(basePtrReg); + *RemainderPtr = remainder; + return; + } + + // If we still have a pending add at this point, emit it now + if (pendingAdd) { + unsigned TmpReg = makeAnotherReg(Type::IntTy); + BuildMI(*MBB, IP, PPC::ADD, 2, TmpReg).addReg(pendingAddReg) + .addReg(basePtrReg); + basePtrReg = TmpReg; + } + + // After we have processed all the indices, the result is left in + // basePtrReg. Move it to the register where we were expected to + // put the answer. + if (remainder->isNullValue()) { + BuildMI (*MBB, IP, PPC::OR, 2, TargetReg).addReg(basePtrReg) + .addReg(basePtrReg); + } else if (canUseAsImmediateForOpcode(remainder, 0)) { + BuildMI(*MBB, IP, PPC::ADDI, 2, TargetReg).addReg(basePtrReg) + .addSImm(remainder->getValue()); + } else { + unsigned Op1r = getReg(remainder, MBB, IP); + BuildMI(*MBB, IP, PPC::ADD, 2, TargetReg).addReg(basePtrReg).addReg(Op1r); + } + } + + /// visitAllocaInst - If this is a fixed size alloca, allocate space from the + /// frame manager, otherwise do it the hard way. + /// + void ISel::visitAllocaInst(AllocaInst &I) { + // If this is a fixed size alloca in the entry block for the function, we + // statically stack allocate the space, so we don't need to do anything here. + // + if (dyn_castFixedAlloca(&I)) return; + + // Find the data size of the alloca inst's getAllocatedType. + const Type *Ty = I.getAllocatedType(); + unsigned TySize = TM.getTargetData().getTypeSize(Ty); + + // Create a register to hold the temporary result of multiplying the type size + // constant by the variable amount. + unsigned TotalSizeReg = makeAnotherReg(Type::UIntTy); + + // TotalSizeReg = mul , + MachineBasicBlock::iterator MBBI = BB->end(); + ConstantUInt *CUI = ConstantUInt::get(Type::UIntTy, TySize); + doMultiplyConst(BB, MBBI, TotalSizeReg, I.getArraySize(), CUI); + + // AddedSize = add , 15 + unsigned AddedSizeReg = makeAnotherReg(Type::UIntTy); + BuildMI(BB, PPC::ADDI, 2, AddedSizeReg).addReg(TotalSizeReg).addSImm(15); + + // AlignedSize = and , ~15 + unsigned AlignedSize = makeAnotherReg(Type::UIntTy); + BuildMI(BB, PPC::RLWINM, 4, AlignedSize).addReg(AddedSizeReg).addImm(0) + .addImm(0).addImm(27); + + // Subtract size from stack pointer, thereby allocating some space. + BuildMI(BB, PPC::SUB, 2, PPC::R1).addReg(PPC::R1).addReg(AlignedSize); + + // Put a pointer to the space into the result register, by copying + // the stack pointer. + BuildMI(BB, PPC::OR, 2, getReg(I)).addReg(PPC::R1).addReg(PPC::R1); + + // Inform the Frame Information that we have just allocated a variable-sized + // object. + F->getFrameInfo()->CreateVariableSizedObject(); + } + + /// visitMallocInst - Malloc instructions are code generated into direct calls + /// to the library malloc. + /// + void ISel::visitMallocInst(MallocInst &I) { + unsigned AllocSize = TM.getTargetData().getTypeSize(I.getAllocatedType()); + unsigned Arg; + + if (ConstantUInt *C = dyn_cast(I.getOperand(0))) { + Arg = getReg(ConstantUInt::get(Type::UIntTy, C->getValue() * AllocSize)); + } else { + Arg = makeAnotherReg(Type::UIntTy); + MachineBasicBlock::iterator MBBI = BB->end(); + ConstantUInt *CUI = ConstantUInt::get(Type::UIntTy, AllocSize); + doMultiplyConst(BB, MBBI, Arg, I.getOperand(0), CUI); + } + + std::vector Args; + Args.push_back(ValueRecord(Arg, Type::UIntTy)); + MachineInstr *TheCall = + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(mallocFn, true); + doCall(ValueRecord(getReg(I), I.getType()), TheCall, Args, false); + TM.CalledFunctions.insert(mallocFn); + } + + + /// visitFreeInst - Free instructions are code gen'd to call the free libc + /// function. + /// + void ISel::visitFreeInst(FreeInst &I) { + std::vector Args; + Args.push_back(ValueRecord(I.getOperand(0))); + MachineInstr *TheCall = + BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(freeFn, true); + doCall(ValueRecord(0, Type::VoidTy), TheCall, Args, false); + TM.CalledFunctions.insert(freeFn); + } + + /// createPPC64ISelSimple - This pass converts an LLVM function into a machine + /// code representation is a very simple peep-hole fashion. + /// + FunctionPass *llvm::createPPC64ISelSimple(TargetMachine &TM) { + return new ISel(TM); + } Index: llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp diff -c /dev/null llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp:1.1 *** /dev/null Wed Aug 11 18:42:26 2004 --- llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp Wed Aug 11 18:42:15 2004 *************** *** 0 **** --- 1,686 ---- + //===-- PPC64AsmPrinter.cpp - Print machine instrs to PowerPC assembly ----===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by the LLVM research group and is distributed under + // the University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file contains a printer that converts from our internal representation + // of machine-dependent LLVM code to PowerPC assembly language. This printer is + // the output mechanism used by `llc'. + // + //===----------------------------------------------------------------------===// + + #define DEBUG_TYPE "asmprinter" + #include "PowerPC.h" + #include "PowerPCInstrInfo.h" + #include "PPC64TargetMachine.h" + #include "llvm/Constants.h" + #include "llvm/DerivedTypes.h" + #include "llvm/Module.h" + #include "llvm/Assembly/Writer.h" + #include "llvm/CodeGen/MachineConstantPool.h" + #include "llvm/CodeGen/MachineFunctionPass.h" + #include "llvm/CodeGen/MachineInstr.h" + #include "llvm/Target/TargetMachine.h" + #include "llvm/Support/Mangler.h" + #include "Support/CommandLine.h" + #include "Support/Debug.h" + #include "Support/MathExtras.h" + #include "Support/Statistic.h" + #include "Support/StringExtras.h" + #include + + namespace llvm { + + namespace { + Statistic<> EmittedInsts("asm-printer", "Number of machine instrs printed"); + + struct Printer : public MachineFunctionPass { + /// Output stream on which we're printing assembly code. + /// + std::ostream &O; + + /// Target machine description which we query for reg. names, data + /// layout, etc. + /// + PPC64TargetMachine &TM; + + /// Name-mangler for global names. + /// + Mangler *Mang; + + /// Map for labels corresponding to global variables + /// + std::map GVToLabelMap; + + Printer(std::ostream &o, TargetMachine &tm) : O(o), + TM(reinterpret_cast(tm)), LabelNumber(0) {} + + /// Cache of mangled name for current function. This is + /// recalculated at the beginning of each call to + /// runOnMachineFunction(). + /// + std::string CurrentFnName; + + /// Unique incrementer for label values for referencing Global values. + /// + unsigned LabelNumber; + + virtual const char *getPassName() const { + return "PPC64 Assembly Printer"; + } + + void printMachineInstruction(const MachineInstr *MI); + void printOp(const MachineOperand &MO, bool elideOffsetKeyword = false); + void printImmOp(const MachineOperand &MO, unsigned ArgType); + void printConstantPool(MachineConstantPool *MCP); + bool runOnMachineFunction(MachineFunction &F); + bool doInitialization(Module &M); + bool doFinalization(Module &M); + void emitGlobalConstant(const Constant* CV); + void emitConstantValueOnly(const Constant *CV); + }; + } // end of anonymous namespace + + /// createPPC64AsmPrinterPass - Returns a pass that prints the PPC + /// assembly code for a MachineFunction to the given output stream, + /// using the given target machine description. This should work + /// regardless of whether the function is in SSA form or not. + /// + FunctionPass *createPPC64AsmPrinter(std::ostream &o,TargetMachine &tm) { + return new Printer(o, tm); + } + + /// isStringCompatible - Can we treat the specified array as a string? + /// Only if it is an array of ubytes or non-negative sbytes. + /// + static bool isStringCompatible(const ConstantArray *CVA) { + const Type *ETy = cast(CVA->getType())->getElementType(); + if (ETy == Type::UByteTy) return true; + if (ETy != Type::SByteTy) return false; + + for (unsigned i = 0; i < CVA->getNumOperands(); ++i) + if (cast(CVA->getOperand(i))->getValue() < 0) + return false; + + return true; + } + + /// toOctal - Convert the low order bits of X into an octal digit. + /// + static inline char toOctal(int X) { + return (X&7)+'0'; + } + + /// getAsCString - Return the specified array as a C compatible + /// string, only if the predicate isStringCompatible is true. + /// + static void printAsCString(std::ostream &O, const ConstantArray *CVA) { + assert(isStringCompatible(CVA) && "Array is not string compatible!"); + + O << "\""; + for (unsigned i = 0; i < CVA->getNumOperands(); ++i) { + unsigned char C = cast(CVA->getOperand(i))->getRawValue(); + + if (C == '"') { + O << "\\\""; + } else if (C == '\\') { + O << "\\\\"; + } else if (isprint(C)) { + O << C; + } else { + switch (C) { + case '\b': O << "\\b"; break; + case '\f': O << "\\f"; break; + case '\n': O << "\\n"; break; + case '\r': O << "\\r"; break; + case '\t': O << "\\t"; break; + default: + O << '\\'; + O << toOctal(C >> 6); + O << toOctal(C >> 3); + O << toOctal(C >> 0); + break; + } + } + } + O << "\""; + } + + // Print out the specified constant, without a storage class. Only the + // constants valid in constant expressions can occur here. + void Printer::emitConstantValueOnly(const Constant *CV) { + if (CV->isNullValue()) + O << "0"; + else if (const ConstantBool *CB = dyn_cast(CV)) { + assert(CB == ConstantBool::True); + O << "1"; + } else if (const ConstantSInt *CI = dyn_cast(CV)) + O << CI->getValue(); + else if (const ConstantUInt *CI = dyn_cast(CV)) + O << CI->getValue(); + else if (const GlobalValue *GV = dyn_cast(CV)) + // This is a constant address for a global variable or function. Use the + // name of the variable or function as the address value. + O << Mang->getValueName(GV); + else if (const ConstantExpr *CE = dyn_cast(CV)) { + const TargetData &TD = TM.getTargetData(); + switch (CE->getOpcode()) { + case Instruction::GetElementPtr: { + // generate a symbolic expression for the byte address + const Constant *ptrVal = CE->getOperand(0); + std::vector idxVec(CE->op_begin()+1, CE->op_end()); + if (unsigned Offset = TD.getIndexedOffset(ptrVal->getType(), idxVec)) { + O << "("; + emitConstantValueOnly(ptrVal); + O << ") + " << Offset; + } else { + emitConstantValueOnly(ptrVal); + } + break; + } + case Instruction::Cast: { + // Support only non-converting or widening casts for now, that is, ones + // that do not involve a change in value. This assertion is really gross, + // and may not even be a complete check. + Constant *Op = CE->getOperand(0); + const Type *OpTy = Op->getType(), *Ty = CE->getType(); + + // Remember, kids, pointers on x86 can be losslessly converted back and + // forth into 32-bit or wider integers, regardless of signedness. :-P + assert(((isa(OpTy) + && (Ty == Type::LongTy || Ty == Type::ULongTy + || Ty == Type::IntTy || Ty == Type::UIntTy)) + || (isa(Ty) + && (OpTy == Type::LongTy || OpTy == Type::ULongTy + || OpTy == Type::IntTy || OpTy == Type::UIntTy)) + || (((TD.getTypeSize(Ty) >= TD.getTypeSize(OpTy)) + && OpTy->isLosslesslyConvertibleTo(Ty)))) + && "FIXME: Don't yet support this kind of constant cast expr"); + O << "("; + emitConstantValueOnly(Op); + O << ")"; + break; + } + case Instruction::Add: + O << "("; + emitConstantValueOnly(CE->getOperand(0)); + O << ") + ("; + emitConstantValueOnly(CE->getOperand(1)); + O << ")"; + break; + default: + assert(0 && "Unsupported operator!"); + } + } else { + assert(0 && "Unknown constant value!"); + } + } + + // Print a constant value or values, with the appropriate storage class as a + // prefix. + void Printer::emitGlobalConstant(const Constant *CV) { + const TargetData &TD = TM.getTargetData(); + + if (const ConstantArray *CVA = dyn_cast(CV)) { + if (isStringCompatible(CVA)) { + O << "\t.byte "; + printAsCString(O, CVA); + O << "\n"; + } else { // Not a string. Print the values in successive locations + for (unsigned i=0, e = CVA->getNumOperands(); i != e; i++) + emitGlobalConstant(CVA->getOperand(i)); + } + return; + } else if (const ConstantStruct *CVS = dyn_cast(CV)) { + // Print the fields in successive locations. Pad to align if needed! + const StructLayout *cvsLayout = TD.getStructLayout(CVS->getType()); + unsigned sizeSoFar = 0; + for (unsigned i = 0, e = CVS->getNumOperands(); i != e; i++) { + const Constant* field = CVS->getOperand(i); + + // Check if padding is needed and insert one or more 0s. + unsigned fieldSize = TD.getTypeSize(field->getType()); + unsigned padSize = ((i == e-1? cvsLayout->StructSize + : cvsLayout->MemberOffsets[i+1]) + - cvsLayout->MemberOffsets[i]) - fieldSize; + sizeSoFar += fieldSize + padSize; + + // Now print the actual field value + emitGlobalConstant(field); + + // Insert the field padding unless it's zero bytes... + if (padSize) + O << "\t.space\t " << padSize << "\n"; + } + assert(sizeSoFar == cvsLayout->StructSize && + "Layout of constant struct may be incorrect!"); + return; + } else if (const ConstantFP *CFP = dyn_cast(CV)) { + // FP Constants are printed as integer constants to avoid losing + // precision... + double Val = CFP->getValue(); + switch (CFP->getType()->getTypeID()) { + default: assert(0 && "Unknown floating point type!"); + case Type::FloatTyID: { + union FU { // Abide by C TBAA rules + float FVal; + unsigned UVal; + } U; + U.FVal = Val; + O << "\t.long " << U.UVal << "\t# float " << Val << "\n"; + return; + } + case Type::DoubleTyID: { + union DU { // Abide by C TBAA rules + double FVal; + uint64_t UVal; + struct { + uint32_t MSWord; + uint32_t LSWord; + } T; + } U; + U.FVal = Val; + + O << ".long " << U.T.MSWord << "\t# double most significant word " + << Val << "\n"; + O << ".long " << U.T.LSWord << "\t# double least significant word " + << Val << "\n"; + return; + } + } + } else if (CV->getType() == Type::ULongTy || CV->getType() == Type::LongTy) { + if (const ConstantInt *CI = dyn_cast(CV)) { + union DU { // Abide by C TBAA rules + int64_t UVal; + struct { + uint32_t MSWord; + uint32_t LSWord; + } T; + } U; + U.UVal = CI->getRawValue(); + + O << ".long " << U.T.MSWord << "\t# Double-word most significant word " + << U.UVal << "\n"; + O << ".long " << U.T.LSWord << "\t# Double-word least significant word " + << U.UVal << "\n"; + return; + } + } + + const Type *type = CV->getType(); + O << "\t"; + switch (type->getTypeID()) { + case Type::UByteTyID: case Type::SByteTyID: + O << "\t.byte"; + break; + case Type::UShortTyID: case Type::ShortTyID: + O << "\t.short"; + break; + case Type::BoolTyID: + case Type::PointerTyID: + case Type::UIntTyID: case Type::IntTyID: + O << "\t.long"; + break; + case Type::ULongTyID: case Type::LongTyID: + assert (0 && "Should have already output double-word constant."); + case Type::FloatTyID: case Type::DoubleTyID: + assert (0 && "Should have already output floating point constant."); + default: + if (CV == Constant::getNullValue(type)) { // Zero initializer? + O << "\t.space " << TD.getTypeSize(type) << "\n"; + return; + } + std::cerr << "Can't handle printing: " << *CV; + abort(); + break; + } + O << ' '; + emitConstantValueOnly(CV); + O << '\n'; + } + + /// printConstantPool - Print to the current output stream assembly + /// representations of the constants in the constant pool MCP. This is + /// used to print out constants which have been "spilled to memory" by + /// the code generator. + /// + void Printer::printConstantPool(MachineConstantPool *MCP) { + const std::vector &CP = MCP->getConstants(); + const TargetData &TD = TM.getTargetData(); + + if (CP.empty()) return; + + for (unsigned i = 0, e = CP.size(); i != e; ++i) { + O << "\t.const\n"; + O << "\t.align " << (unsigned)TD.getTypeAlignment(CP[i]->getType()) + << "\n"; + O << ".CPI" << CurrentFnName << "_" << i << ":\t\t\t\t\t;" + << *CP[i] << "\n"; + emitGlobalConstant(CP[i]); + } + } + + /// runOnMachineFunction - This uses the printMachineInstruction() + /// method to print assembly for each instruction. + /// + bool Printer::runOnMachineFunction(MachineFunction &MF) { + CurrentFnName = MF.getFunction()->getName(); + + // Print out constants referenced by the function + printConstantPool(MF.getConstantPool()); + + // Print out header for the function. + O << "\t.csect .text[PR]\n" + << "\t.align 2\n" + << "\t.globl " << CurrentFnName << '\n' + << "\t.globl ." << CurrentFnName << '\n' + << "\t.csect " << CurrentFnName << "[DS],3\n" + << CurrentFnName << ":\n" + << "\t.llong ." << CurrentFnName << ", TOC[tc0], 0\n" + << "\t.csect .text[PR]\n" + << '.' << CurrentFnName << ":\n"; + + // Print out code for the function. + for (MachineFunction::const_iterator I = MF.begin(), E = MF.end(); + I != E; ++I) { + // Print a label for the basic block. + O << "LBB" << CurrentFnName << "_" << I->getNumber() << ":\t# " + << I->getBasicBlock()->getName() << "\n"; + for (MachineBasicBlock::const_iterator II = I->begin(), E = I->end(); + II != E; ++II) { + // Print the assembly for the instruction. + O << "\t"; + printMachineInstruction(II); + } + } + ++LabelNumber; + + O << "LT.." << CurrentFnName << ":\n" + << "\t.long 0\n" + << "\t.byte 0,0,32,65,128,0,0,0\n" + << "\t.long LT.." << CurrentFnName << "-." << CurrentFnName << '\n' + << "\t.short 3\n" + << "\t.byte \"" << CurrentFnName << "\"\n" + << "\t.align 2\n"; + + // We didn't modify anything. + return false; + } + + void Printer::printOp(const MachineOperand &MO, + bool elideOffsetKeyword /* = false */) { + const MRegisterInfo &RI = *TM.getRegisterInfo(); + int new_symbol; + + switch (MO.getType()) { + case MachineOperand::MO_VirtualRegister: + if (Value *V = MO.getVRegValueOrNull()) { + O << "<" << V->getName() << ">"; + return; + } + // FALLTHROUGH + case MachineOperand::MO_MachineRegister: + case MachineOperand::MO_CCRegister: { + // On AIX, do not print out the 'r' in register names + const char *regName = RI.get(MO.getReg()).Name; + O << ®Name[1]; + return; + } + + case MachineOperand::MO_SignExtendedImmed: + case MachineOperand::MO_UnextendedImmed: + std::cerr << "printOp() does not handle immediate values\n"; + abort(); + return; + + case MachineOperand::MO_PCRelativeDisp: + std::cerr << "Shouldn't use addPCDisp() when building PPC MachineInstrs"; + abort(); + return; + + case MachineOperand::MO_MachineBasicBlock: { + MachineBasicBlock *MBBOp = MO.getMachineBasicBlock(); + O << ".LBB" << Mang->getValueName(MBBOp->getParent()->getFunction()) + << "_" << MBBOp->getNumber() << "\t# " + << MBBOp->getBasicBlock()->getName(); + return; + } + + case MachineOperand::MO_ConstantPoolIndex: + O << ".CPI" << CurrentFnName << "_" << MO.getConstantPoolIndex(); + return; + + case MachineOperand::MO_ExternalSymbol: + O << MO.getSymbolName(); + return; + + case MachineOperand::MO_GlobalAddress: + if (!elideOffsetKeyword) { + GlobalValue *GV = MO.getGlobal(); + + if (Function *F = dyn_cast(GV)) { + O << "." << F->getName(); + } else if (GlobalVariable *GVar = dyn_cast(GV)) { + // output the label name + O << GVToLabelMap[GVar]; + } + } + return; + + default: + O << ""; + return; + } + } + + void Printer::printImmOp(const MachineOperand &MO, unsigned ArgType) { + int Imm = MO.getImmedValue(); + if (ArgType == PPCII::Simm16 || ArgType == PPCII::Disimm16) { + O << (short)Imm; + } else if (ArgType == PPCII::Zimm16) { + O << (unsigned short)Imm; + } else { + O << Imm; + } + } + + /// printMachineInstruction -- Print out a single PPC LLVM instruction + /// MI in Darwin syntax to the current output stream. + /// + void Printer::printMachineInstruction(const MachineInstr *MI) { + unsigned Opcode = MI->getOpcode(); + const TargetInstrInfo &TII = *TM.getInstrInfo(); + const TargetInstrDescriptor &Desc = TII.get(Opcode); + unsigned i; + + unsigned ArgCount = MI->getNumOperands(); + unsigned ArgType[] = { + (Desc.TSFlags >> PPCII::Arg0TypeShift) & PPCII::ArgTypeMask, + (Desc.TSFlags >> PPCII::Arg1TypeShift) & PPCII::ArgTypeMask, + (Desc.TSFlags >> PPCII::Arg2TypeShift) & PPCII::ArgTypeMask, + (Desc.TSFlags >> PPCII::Arg3TypeShift) & PPCII::ArgTypeMask, + (Desc.TSFlags >> PPCII::Arg4TypeShift) & PPCII::ArgTypeMask + }; + assert(((Desc.TSFlags & PPCII::VMX) == 0) && + "Instruction requires VMX support"); + ++EmittedInsts; + + // CALLpcrel and CALLindirect are handled specially here to print only the + // appropriate number of args that the assembler expects. This is because + // may have many arguments appended to record the uses of registers that are + // holding arguments to the called function. + if (Opcode == PPC::COND_BRANCH) { + std::cerr << "Error: untranslated conditional branch psuedo instruction!\n"; + abort(); + } else if (Opcode == PPC::IMPLICIT_DEF) { + O << "# IMPLICIT DEF "; + printOp(MI->getOperand(0)); + O << "\n"; + return; + } else if (Opcode == PPC::CALLpcrel) { + O << TII.getName(Opcode) << " "; + printOp(MI->getOperand(0)); + O << "\n"; + return; + } else if (Opcode == PPC::CALLindirect) { + O << TII.getName(Opcode) << " "; + printImmOp(MI->getOperand(0), ArgType[0]); + O << ", "; + printImmOp(MI->getOperand(1), ArgType[0]); + O << "\n"; + return; + } else if (Opcode == PPC::MovePCtoLR) { + // FIXME: should probably be converted to cout.width and cout.fill + O << "bl \"L0000" << LabelNumber << "$pb\"\n"; + O << "\"L0000" << LabelNumber << "$pb\":\n"; + O << "\tmflr "; + printOp(MI->getOperand(0)); + O << "\n"; + return; + } + + O << TII.getName(Opcode) << " "; + if (Opcode == PPC::LD || Opcode == PPC::LWA || + Opcode == PPC::STDU || Opcode == PPC::STDUX) { + printOp(MI->getOperand(0)); + O << ", "; + MachineOperand MO = MI->getOperand(1); + if (MO.isImmediate()) + printImmOp(MO, ArgType[1]); + else + printOp(MO); + O << "("; + printOp(MI->getOperand(2)); + O << ")\n"; + } else if (Opcode == PPC::BLR || Opcode == PPC::NOP) { + // FIXME: BuildMI() should handle 0 params + O << "\n"; + } else if (ArgCount == 3 && ArgType[1] == PPCII::Disimm16) { + printOp(MI->getOperand(0)); + O << ", "; + printImmOp(MI->getOperand(1), ArgType[1]); + O << "("; + if (MI->getOperand(2).hasAllocatedReg() && + MI->getOperand(2).getReg() == PPC::R0) + O << "0"; + else + printOp(MI->getOperand(2)); + O << ")\n"; + } else { + for (i = 0; i < ArgCount; ++i) { + // addi and friends + if (i == 1 && ArgCount == 3 && ArgType[2] == PPCII::Simm16 && + MI->getOperand(1).hasAllocatedReg() && + MI->getOperand(1).getReg() == PPC::R0) { + O << "0"; + // for long branch support, bc $+8 + } else if (i == 1 && ArgCount == 2 && MI->getOperand(1).isImmediate() && + TII.isBranch(MI->getOpcode())) { + O << "$+8"; + assert(8 == MI->getOperand(i).getImmedValue() + && "branch off PC not to pc+8?"); + //printOp(MI->getOperand(i)); + } else if (MI->getOperand(i).isImmediate()) { + printImmOp(MI->getOperand(i), ArgType[i]); + } else { + printOp(MI->getOperand(i)); + } + if (ArgCount - 1 == i) + O << "\n"; + else + O << ", "; + } + } + } + + // SwitchSection - Switch to the specified section of the executable if we are + // not already in it! + // + static void SwitchSection(std::ostream &OS, std::string &CurSection, + const char *NewSection) { + if (CurSection != NewSection) { + CurSection = NewSection; + if (!CurSection.empty()) + OS << "\t" << NewSection << "\n"; + } + } + + bool Printer::doInitialization(Module &M) { + const TargetData &TD = TM.getTargetData(); + std::string CurSection; + + O << "\t.machine \"ppc64\"\n" + << "\t.toc\n" + << "\t.csect .text[PR]\n"; + + // Print out module-level global variables + for (Module::const_giterator I = M.gbegin(), E = M.gend(); I != E; ++I) { + if (!I->hasInitializer()) + continue; + + std::string Name = I->getName(); + Constant *C = I->getInitializer(); + // N.B.: We are defaulting to writable strings + if (I->hasExternalLinkage()) { + O << "\t.globl " << Name << '\n' + << "\t.csect .data[RW],3\n"; + } else { + O << "\t.csect _global.rw_c[RW],3\n"; + } + O << Name << ":\n"; + emitGlobalConstant(C); + } + + // Output labels for globals + if (M.gbegin() != M.gend()) O << "\t.toc\n"; + for (Module::const_giterator I = M.gbegin(), E = M.gend(); I != E; ++I) { + const GlobalVariable *GV = I; + // Do not output labels for unused variables + if (GV->isExternal() && GV->use_begin() == GV->use_end()) + continue; + + std::string Name = GV->getName(); + std::string Label = "LC.." + utostr(LabelNumber++); + GVToLabelMap[GV] = Label; + O << Label << ":\n" + << "\t.tc " << Name << "[TC]," << Name; + if (GV->isExternal()) O << "[RW]"; + O << '\n'; + } + + Mang = new Mangler(M, true); + return false; // success + } + + bool Printer::doFinalization(Module &M) { + const TargetData &TD = TM.getTargetData(); + // Print out module-level global variables + for (Module::const_giterator I = M.gbegin(), E = M.gend(); I != E; ++I) { + if (I->hasInitializer() || I->hasExternalLinkage()) + continue; + + std::string Name = I->getName(); + if (I->hasInternalLinkage()) { + O << "\t.lcomm " << Name << ",16,_global.bss_c"; + } else { + O << "\t.comm " << Name << "," << TD.getTypeSize(I->getType()) + << "," << log2((unsigned)TD.getTypeAlignment(I->getType())); + } + O << "\t\t# "; + WriteAsOperand(O, I, true, true, &M); + O << "\n"; + } + + O << "_section_.text:\n" + << "\t.csect .data[RW],3\n" + << "\t.llong _section_.text\n"; + + delete Mang; + return false; // success + } + + } // End llvm namespace Index: llvm/lib/Target/PowerPC/PowerPC.h diff -u llvm/lib/Target/PowerPC/PowerPC.h:1.6 llvm/lib/Target/PowerPC/PowerPC.h:1.7 --- llvm/lib/Target/PowerPC/PowerPC.h:1.6 Wed Aug 11 02:40:04 2004 +++ llvm/lib/Target/PowerPC/PowerPC.h Wed Aug 11 18:42:15 2004 @@ -25,8 +25,9 @@ FunctionPass *createPowerPCPEI(); FunctionPass *createPPCBranchSelectionPass(); FunctionPass *createPPC32ISelSimple(TargetMachine &TM); -FunctionPass *createPPC64ISelSimple(TargetMachine &TM); FunctionPass *createPPC32AsmPrinter(std::ostream &OS,TargetMachine &TM); +FunctionPass *createPPC64ISelSimple(TargetMachine &TM); +FunctionPass *createPPC64AsmPrinter(std::ostream &OS,TargetMachine &TM); } // end namespace llvm; From brukman at cs.uiuc.edu Wed Aug 11 18:45:05 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 18:45:05 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp PowerPCRegisterInfo.h PowerPCRegisterInfo.td Message-ID: <200408112345.SAA05483@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCRegisterInfo.cpp updated: 1.26 -> 1.27 PowerPCRegisterInfo.h updated: 1.2 -> 1.3 PowerPCRegisterInfo.td updated: 1.8 -> 1.9 --- Log message: * Set the is64bit boolean flag in PowerPCRegisterInfo * Doubles are 8 bytes in 64-bit PowerPC, and use the general register class * Use double-word loads and stores for restoring from/saving to stack * Do not allocate R2 if compiling for AIX --- Diffs of the changes: (+30 -18) Index: llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp diff -u llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp:1.26 llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp:1.27 --- llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp:1.26 Tue Aug 10 17:47:03 2004 +++ llvm/lib/Target/PowerPC/PowerPCRegisterInfo.cpp Wed Aug 11 18:44:55 2004 @@ -30,9 +30,14 @@ #include using namespace llvm; -PowerPCRegisterInfo::PowerPCRegisterInfo() - : PowerPCGenRegisterInfo(PPC::ADJCALLSTACKDOWN, - PPC::ADJCALLSTACKUP) {} +namespace llvm { + // Switch toggling compilation for AIX + extern cl::opt AIX; +} + +PowerPCRegisterInfo::PowerPCRegisterInfo(bool is64b) + : PowerPCGenRegisterInfo(PPC::ADJCALLSTACKDOWN, PPC::ADJCALLSTACKUP), + is64bit(is64b) {} static unsigned getIdx(const TargetRegisterClass *RC) { if (RC == PowerPC::GPRCRegisterClass) { @@ -41,12 +46,13 @@ case 1: return 0; case 2: return 1; case 4: return 2; + case 8: return 3; } } else if (RC == PowerPC::FPRCRegisterClass) { switch (RC->getSize()) { default: assert(0 && "Invalid data size!"); - case 4: return 3; - case 8: return 4; + case 4: return 4; + case 8: return 5; } } std::cerr << "Invalid register class to getIdx()!\n"; @@ -59,7 +65,7 @@ unsigned SrcReg, int FrameIdx, const TargetRegisterClass *RC) const { static const unsigned Opcode[] = { - PPC::STB, PPC::STH, PPC::STW, PPC::STFS, PPC::STFD + PPC::STB, PPC::STH, PPC::STW, PPC::STD, PPC::STFS, PPC::STFD }; unsigned OC = Opcode[getIdx(RC)]; if (SrcReg == PPC::LR) { @@ -78,7 +84,7 @@ unsigned DestReg, int FrameIdx, const TargetRegisterClass *RC) const { static const unsigned Opcode[] = { - PPC::LBZ, PPC::LHZ, PPC::LWZ, PPC::LFS, PPC::LFD + PPC::LBZ, PPC::LHZ, PPC::LWZ, PPC::LD, PPC::LFS, PPC::LFD }; unsigned OC = Opcode[getIdx(RC)]; if (DestReg == PPC::LR) { @@ -221,17 +227,19 @@ // adjust stack pointer: r1 -= numbytes if (NumBytes <= 32768) { - MI = BuildMI(PPC::STWU, 3).addReg(PPC::R1).addSImm(-NumBytes) + unsigned StoreOpcode = is64bit ? PPC::STDU : PPC::STWU; + MI = BuildMI(StoreOpcode, 3).addReg(PPC::R1).addSImm(-NumBytes) .addReg(PPC::R1); MBB.insert(MBBI, MI); } else { int NegNumbytes = -NumBytes; + unsigned StoreOpcode = is64bit ? PPC::STDUX : PPC::STWUX; MI = BuildMI(PPC::LIS, 1, PPC::R0).addSImm(NegNumbytes >> 16); MBB.insert(MBBI, MI); MI = BuildMI(PPC::ORI, 2, PPC::R0).addReg(PPC::R0) .addImm(NegNumbytes & 0xFFFF); MBB.insert(MBBI, MI); - MI = BuildMI(PPC::STWUX, 3).addReg(PPC::R1).addReg(PPC::R1) + MI = BuildMI(StoreOpcode, 3).addReg(PPC::R1).addReg(PPC::R1) .addReg(PPC::R0); MBB.insert(MBBI, MI); } @@ -249,7 +257,8 @@ unsigned NumBytes = MFI->getStackSize(); if (NumBytes != 0) { - MI = BuildMI(PPC::LWZ, 2, PPC::R1).addSImm(0).addReg(PPC::R1); + unsigned Opcode = is64bit ? PPC::LD : PPC::LWZ; + MI = BuildMI(Opcode, 2, PPC::R1).addSImm(0).addReg(PPC::R1); MBB.insert(MBBI, MI); } } @@ -259,9 +268,10 @@ const TargetRegisterClass* PowerPCRegisterInfo::getRegClassForType(const Type* Ty) const { switch (Ty->getTypeID()) { - case Type::LongTyID: - case Type::ULongTyID: assert(0 && "Long values can't fit in registers!"); default: assert(0 && "Invalid type to getClass!"); + case Type::LongTyID: + case Type::ULongTyID: + if (!is64bit) assert(0 && "Long values can't fit in registers!"); case Type::BoolTyID: case Type::SByteTyID: case Type::UByteTyID: @@ -270,7 +280,7 @@ 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 -u llvm/lib/Target/PowerPC/PowerPCRegisterInfo.h:1.2 llvm/lib/Target/PowerPC/PowerPCRegisterInfo.h:1.3 --- llvm/lib/Target/PowerPC/PowerPCRegisterInfo.h:1.2 Tue Jul 27 13:38:40 2004 +++ llvm/lib/Target/PowerPC/PowerPCRegisterInfo.h Wed Aug 11 18:44:55 2004 @@ -21,8 +21,10 @@ class Type; -struct PowerPCRegisterInfo : public PowerPCGenRegisterInfo { - PowerPCRegisterInfo(); +class PowerPCRegisterInfo : public PowerPCGenRegisterInfo { + bool is64bit; +public: + PowerPCRegisterInfo(bool is64b); const TargetRegisterClass* getRegClassForType(const Type* Ty) const; /// Code Generation virtual methods... Index: llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td diff -u llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td:1.8 llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td:1.9 --- llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td:1.8 Tue Aug 10 17:47:03 2004 +++ llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td Wed Aug 11 18:44:55 2004 @@ -77,13 +77,13 @@ // then nonvolatiles in reverse order since stmw/lmw save from rN to r31 def GPRC : RegisterClass + R16, R15, R14, R13, R0, R2, R1, LR]> { let Methods = [{ iterator allocation_order_end(MachineFunction &MF) const { - return end()-3; + return end() - (AIX ? 4 : 3); } }]; } From brukman at cs.uiuc.edu Wed Aug 11 18:45:54 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 18:45:54 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp PowerPCInstrInfo.h Message-ID: <200408112345.SAA05556@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCInstrInfo.cpp updated: 1.7 -> 1.8 PowerPCInstrInfo.h updated: 1.5 -> 1.6 --- Log message: Set the is64bit flag and propagate it to PowerPCRegisterInfo --- Diffs of the changes: (+6 -3) Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp:1.7 llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp:1.8 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp:1.7 Tue Aug 10 17:47:03 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.cpp Wed Aug 11 18:45:43 2004 @@ -18,8 +18,10 @@ #include using namespace llvm; -PowerPCInstrInfo::PowerPCInstrInfo() - : TargetInstrInfo(PowerPCInsts, sizeof(PowerPCInsts)/sizeof(PowerPCInsts[0])) +PowerPCInstrInfo::PowerPCInstrInfo(bool is64b) + : TargetInstrInfo(PowerPCInsts, sizeof(PowerPCInsts)/sizeof(PowerPCInsts[0])), + RI(is64b), + is64bit(is64b) { } bool PowerPCInstrInfo::isMoveInstr(const MachineInstr& MI, Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.h diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.h:1.5 llvm/lib/Target/PowerPC/PowerPCInstrInfo.h:1.6 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.h:1.5 Tue Aug 10 19:11:25 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.h Wed Aug 11 18:45:43 2004 @@ -64,8 +64,9 @@ class PowerPCInstrInfo : public TargetInstrInfo { const PowerPCRegisterInfo RI; + bool is64bit; public: - PowerPCInstrInfo(); + PowerPCInstrInfo(bool is64b); /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As /// such, whenever a client has an instance of instruction info, it should From brukman at cs.uiuc.edu Wed Aug 11 18:47:19 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 18:47:19 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp PowerPCTargetMachine.h Message-ID: <200408112347.SAA05655@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCTargetMachine.cpp updated: 1.26 -> 1.27 PowerPCTargetMachine.h updated: 1.5 -> 1.6 --- Log message: * Move AIX into the llvm namespace to be accessed from RegisterInfo * Mark InstrInfo with 32 vs. 64 bit flag * Enable the 64-bit isel and asm printer --- Diffs of the changes: (+15 -11) Index: llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp diff -u llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.26 llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.27 --- llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.26 Wed Aug 11 08:35:44 2004 +++ llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp Wed Aug 11 18:47:08 2004 @@ -28,11 +28,13 @@ #include using namespace llvm; +namespace llvm { + cl::opt AIX("aix", + cl::desc("Generate AIX/xcoff instead of Darwin/MachO"), + cl::Hidden); +} + namespace { - cl::opt - AIX("aix", - cl::desc("Generate AIX/xcoff rather than Darwin/macho"), - cl::Hidden); const std::string PPC32 = "PowerPC/32bit"; const std::string PPC64 = "PowerPC/64bit"; @@ -47,8 +49,10 @@ IntrinsicLowering *IL, const TargetData &TD, const TargetFrameInfo &TFI, - const PowerPCJITInfo &TJI) - : TargetMachine(name, IL, TD), FrameInfo(TFI), JITInfo(TJI) {} + const PowerPCJITInfo &TJI, + bool is64b) + : TargetMachine(name, IL, TD), InstrInfo(is64b), FrameInfo(TFI), JITInfo(TJI) +{} unsigned PowerPCTargetMachine::getJITMatchQuality() { #if defined(__POWERPC__) || defined (__ppc__) || defined(_POWER) @@ -80,7 +84,7 @@ PM.add(createUnreachableBlockEliminationPass()); if (LP64) - PM.add(createPPC32ISelSimple(*this)); + PM.add(createPPC64ISelSimple(*this)); else PM.add(createPPC32ISelSimple(*this)); @@ -100,7 +104,7 @@ PM.add(createPPCBranchSelectionPass()); if (AIX) - PM.add(createPPC32AsmPrinter(Out, *this)); + PM.add(createPPC64AsmPrinter(Out, *this)); else PM.add(createPPC32AsmPrinter(Out, *this)); @@ -145,7 +149,7 @@ : PowerPCTargetMachine(PPC32, IL, TargetData(PPC32,false,4,4,4,4,4,4,2,1,4), TargetFrameInfo(TargetFrameInfo::StackGrowsDown,16,0), - PPC32JITInfo(*this)) {} + PPC32JITInfo(*this), false) {} /// PPC64TargetMachine ctor - Create a LP64 architecture model /// @@ -153,7 +157,7 @@ : PowerPCTargetMachine(PPC64, IL, TargetData(PPC64,false,8,4,4,4,4,4,2,1,4), TargetFrameInfo(TargetFrameInfo::StackGrowsDown,16,0), - PPC64JITInfo(*this)) {} + PPC64JITInfo(*this), true) {} unsigned PPC32TargetMachine::getModuleMatchQuality(const Module &M) { if (M.getEndianness() == Module::BigEndian && Index: llvm/lib/Target/PowerPC/PowerPCTargetMachine.h diff -u llvm/lib/Target/PowerPC/PowerPCTargetMachine.h:1.5 llvm/lib/Target/PowerPC/PowerPCTargetMachine.h:1.6 --- llvm/lib/Target/PowerPC/PowerPCTargetMachine.h:1.5 Wed Aug 11 02:40:04 2004 +++ llvm/lib/Target/PowerPC/PowerPCTargetMachine.h Wed Aug 11 18:47:08 2004 @@ -34,7 +34,7 @@ protected: PowerPCTargetMachine(const std::string &name, IntrinsicLowering *IL, const TargetData &TD, const TargetFrameInfo &TFI, - const PowerPCJITInfo &TJI); + const PowerPCJITInfo &TJI, bool is64b); public: virtual const PowerPCInstrInfo *getInstrInfo() const { return &InstrInfo; } virtual const TargetFrameInfo *getFrameInfo() const { return &FrameInfo; } From brukman at cs.uiuc.edu Wed Aug 11 19:10:11 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 19:10:11 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td Message-ID: <200408120010.TAA05988@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCRegisterInfo.td updated: 1.9 -> 1.10 --- Log message: Mark R2 as available for allocation on Darwin/PPC32, but not AIX/PPC64 --- Diffs of the changes: (+6 -3) Index: llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td diff -u llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td:1.9 llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td:1.10 --- llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td:1.9 Wed Aug 11 18:44:55 2004 +++ llvm/lib/Target/PowerPC/PowerPCRegisterInfo.td Wed Aug 11 19:10:01 2004 @@ -77,13 +77,16 @@ // then nonvolatiles in reverse order since stmw/lmw save from rN to r31 def GPRC : RegisterClass + R16, R15, R14, R13, R0, R1, LR]> { let Methods = [{ + iterator allocation_order_begin(MachineFunction &MF) const { + return begin() + (AIX ? 1 : 0); + } iterator allocation_order_end(MachineFunction &MF) const { - return end() - (AIX ? 4 : 3); + return end() - 3; } }]; } From brukman at cs.uiuc.edu Wed Aug 11 20:01:23 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 20:01:23 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp Message-ID: <200408120101.UAA06313@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC64AsmPrinter.cpp updated: 1.1 -> 1.2 --- Log message: Correctly print out ASCII literal strings on AIX --- Diffs of the changes: (+48 -22) Index: llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp diff -u llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp:1.1 llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp:1.2 --- llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp:1.1 Wed Aug 11 18:42:15 2004 +++ llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp Wed Aug 11 20:01:13 2004 @@ -115,39 +115,67 @@ return (X&7)+'0'; } +// Possible states while outputting ASCII strings +namespace { + enum StringSection { + None, + Alpha, + Numeric + }; +} + +/// SwitchStringSection - manage the changes required to output bytes as +/// characters in a string vs. numeric decimal values +/// +static inline void SwitchStringSection(std::ostream &O, StringSection NewSect, + StringSection &Current) { + if (Current == None) { + if (NewSect == Alpha) + O << "\t.byte \""; + else if (NewSect == Numeric) + O << "\t.byte "; + } else if (Current == Alpha) { + if (NewSect == None) + O << "\""; + else if (NewSect == Numeric) + O << "\"\n" + << "\t.byte "; + } else if (Current == Numeric) { + if (NewSect == Alpha) + O << '\n' + << "\t.byte \""; + else if (NewSect == Numeric) + O << ", "; + } + + Current = NewSect; +} + /// getAsCString - Return the specified array as a C compatible /// string, only if the predicate isStringCompatible is true. /// static void printAsCString(std::ostream &O, const ConstantArray *CVA) { assert(isStringCompatible(CVA) && "Array is not string compatible!"); - O << "\""; - for (unsigned i = 0; i < CVA->getNumOperands(); ++i) { - unsigned char C = cast(CVA->getOperand(i))->getRawValue(); + if (CVA->getNumOperands() == 0) + return; + StringSection Current = None; + for (unsigned i = 0, e = CVA->getNumOperands(); i != e; ++i) { + unsigned char C = cast(CVA->getOperand(i))->getRawValue(); if (C == '"') { - O << "\\\""; - } else if (C == '\\') { - O << "\\\\"; + SwitchStringSection(O, Alpha, Current); + O << "\"\""; } else if (isprint(C)) { + SwitchStringSection(O, Alpha, Current); O << C; } else { - switch (C) { - case '\b': O << "\\b"; break; - case '\f': O << "\\f"; break; - case '\n': O << "\\n"; break; - case '\r': O << "\\r"; break; - case '\t': O << "\\t"; break; - default: - O << '\\'; - O << toOctal(C >> 6); - O << toOctal(C >> 3); - O << toOctal(C >> 0); - break; - } + SwitchStringSection(O, Numeric, Current); + O << utostr((unsigned)C); } } - O << "\""; + SwitchStringSection(O, None, Current); + O << '\n'; } // Print out the specified constant, without a storage class. Only the @@ -227,9 +255,7 @@ if (const ConstantArray *CVA = dyn_cast(CV)) { if (isStringCompatible(CVA)) { - O << "\t.byte "; printAsCString(O, CVA); - O << "\n"; } else { // Not a string. Print the values in successive locations for (unsigned i=0, e = CVA->getNumOperands(); i != e; i++) emitGlobalConstant(CVA->getOperand(i)); From lattner at cs.uiuc.edu Wed Aug 11 21:37:00 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 21:37:00 -0500 Subject: [llvm-commits] CVS: llvm/tools/bugpoint/ExtractFunction.cpp Message-ID: <200408120237.VAA20243@zion.cs.uiuc.edu> Changes in directory llvm/tools/bugpoint: ExtractFunction.cpp updated: 1.36 -> 1.37 --- Log message: If the block extractor fails, actually emit the bc file that failed to extract --- Diffs of the changes: (+5 -1) Index: llvm/tools/bugpoint/ExtractFunction.cpp diff -u llvm/tools/bugpoint/ExtractFunction.cpp:1.36 llvm/tools/bugpoint/ExtractFunction.cpp:1.37 --- llvm/tools/bugpoint/ExtractFunction.cpp:1.36 Wed Jul 21 15:50:33 2004 +++ llvm/tools/bugpoint/ExtractFunction.cpp Wed Aug 11 21:36:50 2004 @@ -262,7 +262,11 @@ PI.push_back(getPI(new BlockExtractorPass())); Module *Ret = runPassesOn(M, PI); BlocksToNotExtract.clear(); - if (Ret == 0) + if (Ret == 0) { std::cout << "*** Basic Block extraction failed, please report a bug!\n"; + M = swapProgramIn(M); + EmitProgressBytecode("basicblockextractfail", true); + M = swapProgramIn(M); + } return Ret; } From lattner at cs.uiuc.edu Wed Aug 11 21:44:33 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 21:44:33 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Hello/Hello.cpp Message-ID: <200408120244.VAA21040@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Hello: Hello.cpp updated: 1.4 -> 1.5 --- Log message: Hrm, this pass didn't compile. This bugfix should go into 1.3! --- Diffs of the changes: (+1 -0) Index: llvm/lib/Transforms/Hello/Hello.cpp diff -u llvm/lib/Transforms/Hello/Hello.cpp:1.4 llvm/lib/Transforms/Hello/Hello.cpp:1.5 --- llvm/lib/Transforms/Hello/Hello.cpp:1.4 Fri Jan 9 00:11:43 2004 +++ llvm/lib/Transforms/Hello/Hello.cpp Wed Aug 11 21:44:23 2004 @@ -14,6 +14,7 @@ #include "llvm/Pass.h" #include "llvm/Function.h" +#include using namespace llvm; namespace { From brukman at cs.uiuc.edu Wed Aug 11 21:51:48 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 21:51:48 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp Message-ID: <200408120251.VAA21930@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC64AsmPrinter.cpp updated: 1.2 -> 1.3 --- Log message: Eliminate special-casing 14-bit immediate load/store opcodes --- Diffs of the changes: (+5 -16) Index: llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp diff -u llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp:1.2 llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp:1.3 --- llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp:1.2 Wed Aug 11 20:01:13 2004 +++ llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp Wed Aug 11 21:51:38 2004 @@ -570,8 +570,11 @@ } O << TII.getName(Opcode) << " "; - if (Opcode == PPC::LD || Opcode == PPC::LWA || - Opcode == PPC::STDU || Opcode == PPC::STDUX) { + if (Opcode == PPC::BLR || Opcode == PPC::NOP) { + // FIXME: BuildMI() should handle 0 params + O << "\n"; + } else if (ArgCount == 3 && + (ArgType[1] == PPCII::Disimm16 || ArgType[1] == PPCII::Disimm14)) { printOp(MI->getOperand(0)); O << ", "; MachineOperand MO = MI->getOperand(1); @@ -582,20 +585,6 @@ O << "("; printOp(MI->getOperand(2)); O << ")\n"; - } else if (Opcode == PPC::BLR || Opcode == PPC::NOP) { - // FIXME: BuildMI() should handle 0 params - O << "\n"; - } else if (ArgCount == 3 && ArgType[1] == PPCII::Disimm16) { - printOp(MI->getOperand(0)); - O << ", "; - printImmOp(MI->getOperand(1), ArgType[1]); - O << "("; - if (MI->getOperand(2).hasAllocatedReg() && - MI->getOperand(2).getReg() == PPC::R0) - O << "0"; - else - printOp(MI->getOperand(2)); - O << ")\n"; } else { for (i = 0; i < ArgCount; ++i) { // addi and friends From brukman at cs.uiuc.edu Wed Aug 11 21:53:12 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 21:53:12 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp Message-ID: <200408120253.VAA22039@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC64ISelSimple.cpp updated: 1.1 -> 1.2 --- Log message: * Pointers are 8 bytes, hence cLong type on 64-bit PPC * Fix loading of GlobalValues --- Diffs of the changes: (+8 -6) Index: llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp diff -u llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp:1.1 llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp:1.2 --- llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp:1.1 Wed Aug 11 18:42:15 2004 +++ llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp Wed Aug 11 21:53:01 2004 @@ -52,14 +52,14 @@ case Type::ShortTyID: case Type::UShortTyID: return cShort; // Short operands are class #1 case Type::IntTyID: - case Type::UIntTyID: - case Type::PointerTyID: return cInt; // Ints and pointers are class #2 + case Type::UIntTyID: return cInt; // Ints are class #2 case Type::FloatTyID: return cFP32; // Single float is #3 case Type::DoubleTyID: return cFP64; // Double Point is #4 + case Type::PointerTyID: case Type::LongTyID: - case Type::ULongTyID: return cLong; // Longs are class #5 + case Type::ULongTyID: return cLong; // Longs and pointers are class #5 default: assert(0 && "Invalid type to getClass!"); return cByte; // not reached @@ -606,9 +606,11 @@ // Copy zero (null pointer) to the register. BuildMI(*MBB, IP, PPC::LI, 1, R).addSImm(0); } else if (GlobalValue *GV = dyn_cast(C)) { - unsigned TmpReg = makeAnotherReg(GV->getType()); - BuildMI(*MBB, IP, PPC::LD, 2, TmpReg).addGlobalAddress(GV).addReg(PPC::R2); - BuildMI(*MBB, IP, PPC::LWA, 2, R).addSImm(0).addReg(TmpReg); + static unsigned OpcodeTable[] = { + PPC::LBZ, PPC::LHZ, PPC::LWZ, PPC::LFS, PPC::LFD, PPC::LD + }; + unsigned Opcode = OpcodeTable[getClassB(GV->getType())]; + BuildMI(*MBB, IP, Opcode, 2, R).addGlobalAddress(GV).addReg(PPC::R2); } else { std::cerr << "Offending constant: " << *C << "\n"; assert(0 && "Type not handled yet!"); From lattner at cs.uiuc.edu Wed Aug 11 22:17:13 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Wed, 11 Aug 2004 22:17:13 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/CodeExtractor.cpp Message-ID: <200408120317.WAA23933@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: CodeExtractor.cpp updated: 1.27 -> 1.28 --- Log message: Fix code extraction of unwind blocks. This fixed bugs that bugpoint can run into. This should go into 1.3 --- Diffs of the changes: (+12 -9) Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp diff -u llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.27 llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.28 --- llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.27 Wed Jul 21 15:50:33 2004 +++ llvm/lib/Transforms/Utils/CodeExtractor.cpp Wed Aug 11 22:17:02 2004 @@ -513,21 +513,24 @@ } // Now that we've done the deed, simplify the switch instruction. + const Type *OldFnRetTy = TheSwitch->getParent()->getParent()->getReturnType(); switch (NumExitBlocks) { case 0: - // There is only 1 successor (the block containing the switch itself), which + // There are no successors (the block containing the switch itself), which // means that previously this was the last part of the function, and hence // this should be rewritten as a `ret' // Check if the function should return a value - if (TheSwitch->getParent()->getParent()->getReturnType() != Type::VoidTy && - TheSwitch->getParent()->getParent()->getReturnType() == - TheSwitch->getCondition()->getType()) + if (OldFnRetTy == Type::VoidTy) { + new ReturnInst(0, TheSwitch); // Return void + } else if (OldFnRetTy == TheSwitch->getCondition()->getType()) { // return what we have new ReturnInst(TheSwitch->getCondition(), TheSwitch); - else - // just return - new ReturnInst(0, TheSwitch); + } else { + // Otherwise we must have code extracted an unwind or something, just + // return whatever we want. + new ReturnInst(Constant::getNullValue(OldFnRetTy), TheSwitch); + } TheSwitch->getParent()->getInstList().erase(TheSwitch); break; @@ -583,8 +586,8 @@ /// for each scalar output in the function: at every exit, store intermediate /// computed result back into memory. /// -Function *CodeExtractor::ExtractCodeRegion(const std::vector &code) -{ +Function *CodeExtractor:: +ExtractCodeRegion(const std::vector &code) { if (!isEligible(code)) return 0; From brukman at cs.uiuc.edu Wed Aug 11 22:28:57 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 22:28:57 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp Message-ID: <200408120328.WAA24588@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC64AsmPrinter.cpp updated: 1.3 -> 1.4 --- Log message: * Print out full names for non-GPR or -FPR registers * BuildMI() really *does* handle 0 params! --- Diffs of the changes: (+5 -3) Index: llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp diff -u llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp:1.3 llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp:1.4 --- llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp:1.3 Wed Aug 11 21:51:38 2004 +++ llvm/lib/Target/PowerPC/PPC64AsmPrinter.cpp Wed Aug 11 22:28:47 2004 @@ -451,9 +451,12 @@ // FALLTHROUGH case MachineOperand::MO_MachineRegister: case MachineOperand::MO_CCRegister: { - // On AIX, do not print out the 'r' in register names + // On AIX, do not print out the 'R' (GPR) or 'F' (FPR) in reg names const char *regName = RI.get(MO.getReg()).Name; - O << ®Name[1]; + if (regName[0] == 'R' || regName[0] == 'F') + O << ®Name[1]; + else + O << regName; return; } @@ -571,7 +574,6 @@ O << TII.getName(Opcode) << " "; if (Opcode == PPC::BLR || Opcode == PPC::NOP) { - // FIXME: BuildMI() should handle 0 params O << "\n"; } else if (ArgCount == 3 && (ArgType[1] == PPCII::Disimm16 || ArgType[1] == PPCII::Disimm14)) { From brukman at cs.uiuc.edu Wed Aug 11 22:30:13 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Wed, 11 Aug 2004 22:30:13 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp Message-ID: <200408120330.WAA24668@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC64ISelSimple.cpp updated: 1.2 -> 1.3 --- Log message: * Correct 64-bit version: blr 1 (not 0) * BuildMI() can build 0-param instructions (e.g., NOP) --- Diffs of the changes: (+2 -2) Index: llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp diff -u llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp:1.2 llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp:1.3 --- llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp:1.2 Wed Aug 11 21:53:01 2004 +++ llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp Wed Aug 11 22:30:03 2004 @@ -1222,7 +1222,7 @@ visitInstruction(I); } } - BuildMI(BB, PPC::BLR, 1).addImm(0); + BuildMI(BB, PPC::BLR, 1).addImm(1); } // getBlockAfter - Return the basic block which occurs lexically after the @@ -1457,7 +1457,7 @@ BuildMI(BB, PPC::IMPLICIT_DEF, 0, PPC::LR); BB->push_back(CallMI); - BuildMI(BB, PPC::NOP, 1).addImm(0); + BuildMI(BB, PPC::NOP, 0); // These functions are automatically eliminated by the prolog/epilog pass BuildMI(BB, PPC::ADJCALLSTACKUP, 1).addImm(NumBytes); From lattner at cs.uiuc.edu Thu Aug 12 00:27:19 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 00:27:19 -0500 Subject: [llvm-commits] CVS: llvm/test/Programs/SingleSource/Regression/C/2004-08-12-InlinerAndAllocas.c Message-ID: <200408120527.AAA27232@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/SingleSource/Regression/C: 2004-08-12-InlinerAndAllocas.c added (r1.1) --- Log message: New testcase --- Diffs of the changes: (+21 -0) Index: llvm/test/Programs/SingleSource/Regression/C/2004-08-12-InlinerAndAllocas.c diff -c /dev/null llvm/test/Programs/SingleSource/Regression/C/2004-08-12-InlinerAndAllocas.c:1.1 *** /dev/null Thu Aug 12 00:27:19 2004 --- llvm/test/Programs/SingleSource/Regression/C/2004-08-12-InlinerAndAllocas.c Thu Aug 12 00:27:09 2004 *************** *** 0 **** --- 1,21 ---- + // A compiler cannot inline Callee into main unless it is prepared to reclaim + // the stack memory allocated in it. + + #include + #include + + static int Callee(int i) { + if (i != 0) { + char *X = alloca(1000); + sprintf(X, "%d\n", i); + return X[0]; + } + return 0; + } + + int main() { + int i, j = 0; + for (i = 0; i < 10000; ++i) + j += Callee(i); + printf("%d\n", j); + } From lattner at cs.uiuc.edu Thu Aug 12 00:45:19 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 00:45:19 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/IPO/InlineSimple.cpp Message-ID: <200408120545.AAA28457@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: InlineSimple.cpp updated: 1.63 -> 1.64 --- Log message: This patch makes the inliner refuse to inline functions that have alloca instructions in the body of the function (not the entry block). This fixes test/Programs/SingleSource/Regression/C/2004-08-12-InlinerAndAllocas.c and test/Programs/External/SPEC/CINT2000/176.gcc on zion. This should obviously be pulled into 1.3. --- Diffs of the changes: (+58 -26) Index: llvm/lib/Transforms/IPO/InlineSimple.cpp diff -u llvm/lib/Transforms/IPO/InlineSimple.cpp:1.63 llvm/lib/Transforms/IPO/InlineSimple.cpp:1.64 --- llvm/lib/Transforms/IPO/InlineSimple.cpp:1.63 Sat Jul 17 19:27:06 2004 +++ llvm/lib/Transforms/IPO/InlineSimple.cpp Thu Aug 12 00:45:09 2004 @@ -31,6 +31,16 @@ // FunctionInfo - For each function, calculate the size of it in blocks and // instructions. struct FunctionInfo { + // HasAllocas - Keep track of whether or not a function contains an alloca + // instruction that is not in the entry block of the function. Inlining + // this call could cause us to blow out the stack, because the stack memory + // would never be released. + // + // FIXME: LLVM needs a way of dealloca'ing memory, which would make this + // irrelevant! + // + bool HasAllocas; + // NumInsts, NumBlocks - Keep track of how large each function is, which is // used to estimate the code size cost of inlining it. unsigned NumInsts, NumBlocks; @@ -41,7 +51,11 @@ // entry here. std::vector ArgumentWeights; - FunctionInfo() : NumInsts(0), NumBlocks(0) {} + FunctionInfo() : HasAllocas(false), NumInsts(0), NumBlocks(0) {} + + /// analyzeFunction - Fill in the current structure with information gleaned + /// from the specified function. + void analyzeFunction(Function *F); }; class SimpleInliner : public Inliner { @@ -123,6 +137,41 @@ return Reduction; } +/// analyzeFunction - Fill in the current structure with information gleaned +/// from the specified function. +void FunctionInfo::analyzeFunction(Function *F) { + unsigned NumInsts = 0, NumBlocks = 0; + + // Look at the size of the callee. Each basic block counts as 20 units, and + // each instruction counts as 10. + for (Function::const_iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { + for (BasicBlock::const_iterator II = BB->begin(), E = BB->end(); + II != E; ++II) { + ++NumInsts; + + // If there is an alloca in the body of the function, we cannot currently + // inline the function without the risk of exploding the stack. + if (isa(II) && BB != F->begin()) { + HasAllocas = true; + this->NumBlocks = this->NumInsts = 1; + return; + } + } + + ++NumBlocks; + } + + this->NumBlocks = NumBlocks; + this->NumInsts = NumInsts; + + // Check out all of the arguments to the function, figuring out how much + // code can be eliminated if one of the arguments is a constant. + for (Function::aiterator I = F->abegin(), E = F->aend(); I != E; ++I) + ArgumentWeights.push_back(ArgInfo(CountCodeReductionForConstant(I), + CountCodeReductionForAlloca(I))); +} + + // getInlineCost - The heuristic used to determine if we should inline the // function call or not. // @@ -149,31 +198,14 @@ // Get information about the callee... FunctionInfo &CalleeFI = CachedFunctionInfo[Callee]; - // If we haven't calculated this information yet... - if (CalleeFI.NumBlocks == 0) { - unsigned NumInsts = 0, NumBlocks = 0; - - // Look at the size of the callee. Each basic block counts as 20 units, and - // each instruction counts as 10. - for (Function::const_iterator BB = Callee->begin(), E = Callee->end(); - BB != E; ++BB) { - NumInsts += BB->size(); - NumBlocks++; - } - - CalleeFI.NumBlocks = NumBlocks; - CalleeFI.NumInsts = NumInsts; - - // Check out all of the arguments to the function, figuring out how much - // code can be eliminated if one of the arguments is a constant. - std::vector &ArgWeights = CalleeFI.ArgumentWeights; - - for (Function::aiterator I = Callee->abegin(), E = Callee->aend(); - I != E; ++I) - ArgWeights.push_back(ArgInfo(CountCodeReductionForConstant(I), - CountCodeReductionForAlloca(I))); - } - + // If we haven't calculated this information yet, do so now. + if (CalleeFI.NumBlocks == 0) + CalleeFI.analyzeFunction(Callee); + + // Don't inline calls to functions with allocas that are not in the entry + // block of the function. + if (CalleeFI.HasAllocas) + return 2000000000; // Add to the inline quality for properties that make the call valuable to // inline. This includes factors that indicate that the result of inlining From criswell at cs.uiuc.edu Thu Aug 12 09:21:03 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Thu, 12 Aug 2004 09:21:03 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/lib/Transforms/IPO/InlineSimple.cpp Message-ID: <200408121421.JAA32065@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: InlineSimple.cpp updated: 1.63 -> 1.63.2.1 --- Log message: Merged from mainline. This should fix 176.gcc. --- Diffs of the changes: (+58 -26) Index: llvm/lib/Transforms/IPO/InlineSimple.cpp diff -u llvm/lib/Transforms/IPO/InlineSimple.cpp:1.63 llvm/lib/Transforms/IPO/InlineSimple.cpp:1.63.2.1 --- llvm/lib/Transforms/IPO/InlineSimple.cpp:1.63 Sat Jul 17 19:27:06 2004 +++ llvm/lib/Transforms/IPO/InlineSimple.cpp Thu Aug 12 09:20:45 2004 @@ -31,6 +31,16 @@ // FunctionInfo - For each function, calculate the size of it in blocks and // instructions. struct FunctionInfo { + // HasAllocas - Keep track of whether or not a function contains an alloca + // instruction that is not in the entry block of the function. Inlining + // this call could cause us to blow out the stack, because the stack memory + // would never be released. + // + // FIXME: LLVM needs a way of dealloca'ing memory, which would make this + // irrelevant! + // + bool HasAllocas; + // NumInsts, NumBlocks - Keep track of how large each function is, which is // used to estimate the code size cost of inlining it. unsigned NumInsts, NumBlocks; @@ -41,7 +51,11 @@ // entry here. std::vector ArgumentWeights; - FunctionInfo() : NumInsts(0), NumBlocks(0) {} + FunctionInfo() : HasAllocas(false), NumInsts(0), NumBlocks(0) {} + + /// analyzeFunction - Fill in the current structure with information gleaned + /// from the specified function. + void analyzeFunction(Function *F); }; class SimpleInliner : public Inliner { @@ -123,6 +137,41 @@ return Reduction; } +/// analyzeFunction - Fill in the current structure with information gleaned +/// from the specified function. +void FunctionInfo::analyzeFunction(Function *F) { + unsigned NumInsts = 0, NumBlocks = 0; + + // Look at the size of the callee. Each basic block counts as 20 units, and + // each instruction counts as 10. + for (Function::const_iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { + for (BasicBlock::const_iterator II = BB->begin(), E = BB->end(); + II != E; ++II) { + ++NumInsts; + + // If there is an alloca in the body of the function, we cannot currently + // inline the function without the risk of exploding the stack. + if (isa(II) && BB != F->begin()) { + HasAllocas = true; + this->NumBlocks = this->NumInsts = 1; + return; + } + } + + ++NumBlocks; + } + + this->NumBlocks = NumBlocks; + this->NumInsts = NumInsts; + + // Check out all of the arguments to the function, figuring out how much + // code can be eliminated if one of the arguments is a constant. + for (Function::aiterator I = F->abegin(), E = F->aend(); I != E; ++I) + ArgumentWeights.push_back(ArgInfo(CountCodeReductionForConstant(I), + CountCodeReductionForAlloca(I))); +} + + // getInlineCost - The heuristic used to determine if we should inline the // function call or not. // @@ -149,31 +198,14 @@ // Get information about the callee... FunctionInfo &CalleeFI = CachedFunctionInfo[Callee]; - // If we haven't calculated this information yet... - if (CalleeFI.NumBlocks == 0) { - unsigned NumInsts = 0, NumBlocks = 0; - - // Look at the size of the callee. Each basic block counts as 20 units, and - // each instruction counts as 10. - for (Function::const_iterator BB = Callee->begin(), E = Callee->end(); - BB != E; ++BB) { - NumInsts += BB->size(); - NumBlocks++; - } - - CalleeFI.NumBlocks = NumBlocks; - CalleeFI.NumInsts = NumInsts; - - // Check out all of the arguments to the function, figuring out how much - // code can be eliminated if one of the arguments is a constant. - std::vector &ArgWeights = CalleeFI.ArgumentWeights; - - for (Function::aiterator I = Callee->abegin(), E = Callee->aend(); - I != E; ++I) - ArgWeights.push_back(ArgInfo(CountCodeReductionForConstant(I), - CountCodeReductionForAlloca(I))); - } - + // If we haven't calculated this information yet, do so now. + if (CalleeFI.NumBlocks == 0) + CalleeFI.analyzeFunction(Callee); + + // Don't inline calls to functions with allocas that are not in the entry + // block of the function. + if (CalleeFI.HasAllocas) + return 2000000000; // Add to the inline quality for properties that make the call valuable to // inline. This includes factors that indicate that the result of inlining From criswell at cs.uiuc.edu Thu Aug 12 09:28:23 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Thu, 12 Aug 2004 09:28:23 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/lib/Transforms/Hello/Hello.cpp Message-ID: <200408121428.JAA32176@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Hello: Hello.cpp updated: 1.4 -> 1.4.8.1 --- Log message: Merged from mainline. --- Diffs of the changes: (+1 -0) Index: llvm/lib/Transforms/Hello/Hello.cpp diff -u llvm/lib/Transforms/Hello/Hello.cpp:1.4 llvm/lib/Transforms/Hello/Hello.cpp:1.4.8.1 --- llvm/lib/Transforms/Hello/Hello.cpp:1.4 Fri Jan 9 00:11:43 2004 +++ llvm/lib/Transforms/Hello/Hello.cpp Thu Aug 12 09:28:12 2004 @@ -14,6 +14,7 @@ #include "llvm/Pass.h" #include "llvm/Function.h" +#include using namespace llvm; namespace { From criswell at cs.uiuc.edu Thu Aug 12 09:28:55 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Thu, 12 Aug 2004 09:28:55 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/lib/Transforms/Utils/CodeExtractor.cpp Message-ID: <200408121428.JAA32242@zion.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: CodeExtractor.cpp updated: 1.27 -> 1.27.2.1 --- Log message: Merged from mainline. --- Diffs of the changes: (+12 -9) Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp diff -u llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.27 llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.27.2.1 --- llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.27 Wed Jul 21 15:50:33 2004 +++ llvm/lib/Transforms/Utils/CodeExtractor.cpp Thu Aug 12 09:28:44 2004 @@ -513,21 +513,24 @@ } // Now that we've done the deed, simplify the switch instruction. + const Type *OldFnRetTy = TheSwitch->getParent()->getParent()->getReturnType(); switch (NumExitBlocks) { case 0: - // There is only 1 successor (the block containing the switch itself), which + // There are no successors (the block containing the switch itself), which // means that previously this was the last part of the function, and hence // this should be rewritten as a `ret' // Check if the function should return a value - if (TheSwitch->getParent()->getParent()->getReturnType() != Type::VoidTy && - TheSwitch->getParent()->getParent()->getReturnType() == - TheSwitch->getCondition()->getType()) + if (OldFnRetTy == Type::VoidTy) { + new ReturnInst(0, TheSwitch); // Return void + } else if (OldFnRetTy == TheSwitch->getCondition()->getType()) { // return what we have new ReturnInst(TheSwitch->getCondition(), TheSwitch); - else - // just return - new ReturnInst(0, TheSwitch); + } else { + // Otherwise we must have code extracted an unwind or something, just + // return whatever we want. + new ReturnInst(Constant::getNullValue(OldFnRetTy), TheSwitch); + } TheSwitch->getParent()->getInstList().erase(TheSwitch); break; @@ -583,8 +586,8 @@ /// for each scalar output in the function: at every exit, store intermediate /// computed result back into memory. /// -Function *CodeExtractor::ExtractCodeRegion(const std::vector &code) -{ +Function *CodeExtractor:: +ExtractCodeRegion(const std::vector &code) { if (!isEligible(code)) return 0; From criswell at cs.uiuc.edu Thu Aug 12 09:34:49 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Thu, 12 Aug 2004 09:34:49 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/utils/mkrel.sh Message-ID: <200408121434.JAA32390@zion.cs.uiuc.edu> Changes in directory llvm/utils: mkrel.sh updated: 1.1.2.1 -> 1.1.2.2 --- Log message: Setup the llvm-gcc tarball the way we have always done. --- Diffs of the changes: (+10 -2) Index: llvm/utils/mkrel.sh diff -u llvm/utils/mkrel.sh:1.1.2.1 llvm/utils/mkrel.sh:1.1.2.2 --- llvm/utils/mkrel.sh:1.1.2.1 Fri Aug 6 16:03:59 2004 +++ llvm/utils/mkrel.sh Thu Aug 12 09:34:38 2004 @@ -27,15 +27,23 @@ # Create the working directory and make it the current directory. # mkdir -p $dir +echo "Changing directory to $dir" cd $dir # # Extract the LLVM sources given the label. # +echo "Extracting source $tag from $cvsroot" cvs -d $cvsroot export -r $tag llvm llvm-gcc # +# Move the llvm-gcc sources so that they match what is used by end-users. +# +mkdir -p cfrontend +mv llvm-gcc cfrontend/src + +# # Create source tarballs. # -tar -cvf - llvm | gzip > llvm-${version}.tar.gz -tar -cvf - llvm-gcc | gzip > cfrontend-${version}.source.tar.gz +tar -cf - llvm | gzip > llvm-${version}.tar.gz +tar -cf - cfrontend | gzip > cfrontend-${version}.source.tar.gz From brukman at cs.uiuc.edu Thu Aug 12 12:16:53 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Thu, 12 Aug 2004 12:16:53 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp Message-ID: <200408121716.MAA01070@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCTargetMachine.cpp updated: 1.27 -> 1.28 --- Log message: Disable PPC64 backend by default because LLC cannot choose automatically between SparcV9 and PowerPC64 without target triples, since they are both 64-bit big-endian targets. --- Diffs of the changes: (+2 -2) Index: llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp diff -u llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.27 llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.28 --- llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp:1.27 Wed Aug 11 18:47:08 2004 +++ llvm/lib/Target/PowerPC/PowerPCTargetMachine.cpp Thu Aug 12 12:16:43 2004 @@ -41,8 +41,8 @@ // Register the targets RegisterTarget X("ppc32", " PowerPC 32-bit (experimental)"); - RegisterTarget - Y("ppc64", " PowerPC 64-bit (unimplemented)"); + //RegisterTarget + //Y("ppc64", " PowerPC 64-bit (unimplemented)"); } PowerPCTargetMachine::PowerPCTargetMachine(const std::string &name, From reid at x10sys.com Thu Aug 12 12:52:57 2004 From: reid at x10sys.com (Reid Spencer) Date: Thu, 12 Aug 2004 12:52:57 -0500 Subject: [llvm-commits] CVS: llvm/projects/HowToUseJIT/HowToUseJIT.cpp Message-ID: <200408121752.MAA01251@zion.cs.uiuc.edu> Changes in directory llvm/projects/HowToUseJIT: HowToUseJIT.cpp updated: 1.2 -> 1.3 --- Log message: Convert to unix line format. --- Diffs of the changes: (+151 -151) Index: llvm/projects/HowToUseJIT/HowToUseJIT.cpp diff -u llvm/projects/HowToUseJIT/HowToUseJIT.cpp:1.2 llvm/projects/HowToUseJIT/HowToUseJIT.cpp:1.3 --- llvm/projects/HowToUseJIT/HowToUseJIT.cpp:1.2 Tue Aug 10 14:18:51 2004 +++ llvm/projects/HowToUseJIT/HowToUseJIT.cpp Thu Aug 12 12:52:47 2004 @@ -1,151 +1,151 @@ -//===--- HowToUseJIT.cpp - An example use of the JIT ----------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file was developed by Valery A. Khamenya and is distributed under the -// University of Illinois Open Source License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This small program provides an example of how to quickly build a small -// module with two functions and execute it with the JIT. -// -//===------------------------------------------------------------------------=== - -// Goal: -// The goal of this snippet is to create in the memory -// the LLVM module consisting of two functions as follow: -// -// int add1(int x) { -// return x+1; -// } -// -// int foo() { -// return add1(10); -// } -// -// then compile the module via JIT, then execute the `foo' -// function and return result to a driver, i.e. to a "host program". -// -// Some remarks and questions: -// -// - could we invoke some code using noname functions too? -// e.g. evaluate "foo()+foo()" without fears to introduce -// conflict of temporary function name with some real -// existing function name? -// - -#include - -#include -#include -#include -#include -#include - -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/GenericValue.h" - - -using namespace llvm; - -int main() { - - // Create some module to put our function into it. - Module *M = new Module("test"); - - - // We are about to create the add1 function: - Function *Add1F; - - { - // first create type for the single argument of add1 function: - // the type is 'int ()' - std::vector ArgT(1); - ArgT[0] = Type::IntTy; - - // now create full type of the add1 function: - FunctionType *Add1T = FunctionType::get(Type::IntTy, // type of result - ArgT, - /*not vararg*/false); - - // Now create the add1 function entry and - // insert this entry into module M - // (By passing a module as the last parameter to the Function constructor, - // it automatically gets appended to the Module.) - Add1F = new Function(Add1T, - Function::ExternalLinkage, // maybe too much - "add1", M); - - // Add a basic block to the function... (again, it automatically inserts - // because of the last argument.) - BasicBlock *BB = new BasicBlock("EntryBlock of add1 function", Add1F); - - // Get pointers to the constant `1'... - Value *One = ConstantSInt::get(Type::IntTy, 1); - - // Get pointers to the integer argument of the add1 function... - assert(Add1F->abegin() != Add1F->aend()); // Make sure there's an arg - Argument &ArgX = Add1F->afront(); // Get the arg - - // Create the add instruction... does not insert... - Instruction *Add = BinaryOperator::create(Instruction::Add, One, &ArgX, - "addresult"); - - // explicitly insert it into the basic block... - BB->getInstList().push_back(Add); - - // Create the return instruction and add it to the basic block - BB->getInstList().push_back(new ReturnInst(Add)); - - // function add1 is ready - } - - - // now we going to create function `foo': - Function *FooF; - - { - // Create the foo function type: - FunctionType *FooT = - FunctionType::get(Type::IntTy, // result has type: 'int ()' - std::vector(), // no arguments - /*not vararg*/false); - - // create the entry for function `foo' and insert - // this entry into module M: - FooF = - new Function(FooT, - Function::ExternalLinkage, // too wide? - "foo", M); - - // Add a basic block to the FooF function... - BasicBlock *BB = new BasicBlock("EntryBlock of add1 function", FooF); - - // Get pointers to the constant `10'... - Value *Ten = ConstantSInt::get(Type::IntTy, 10); - - // Put the argument Ten on stack and make call: - // ... - std::vector Params; - Params.push_back(Ten); - CallInst * Add1CallRes = new CallInst(Add1F, Params, "add1", BB); - - // Create the return instruction and add it to the basic block - BB->getInstList().push_back(new ReturnInst(Add1CallRes)); - - } - - // Now we going to create JIT ?? - ExistingModuleProvider* MP = new ExistingModuleProvider(M); - ExecutionEngine* EE = ExecutionEngine::create( MP, true ); - - // Call the `foo' function with no arguments: - std::vector noargs; - GenericValue gv = EE->runFunction(FooF, noargs); - - // import result of execution: - std::cout << "Result: " << gv.IntVal << std:: endl; - - return 0; -} +//===--- HowToUseJIT.cpp - An example use of the JIT ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Valery A. Khamenya and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This small program provides an example of how to quickly build a small +// module with two functions and execute it with the JIT. +// +//===------------------------------------------------------------------------=== + +// Goal: +// The goal of this snippet is to create in the memory +// the LLVM module consisting of two functions as follow: +// +// int add1(int x) { +// return x+1; +// } +// +// int foo() { +// return add1(10); +// } +// +// then compile the module via JIT, then execute the `foo' +// function and return result to a driver, i.e. to a "host program". +// +// Some remarks and questions: +// +// - could we invoke some code using noname functions too? +// e.g. evaluate "foo()+foo()" without fears to introduce +// conflict of temporary function name with some real +// existing function name? +// + +#include + +#include +#include +#include +#include +#include + +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/GenericValue.h" + + +using namespace llvm; + +int main() { + + // Create some module to put our function into it. + Module *M = new Module("test"); + + + // We are about to create the add1 function: + Function *Add1F; + + { + // first create type for the single argument of add1 function: + // the type is 'int ()' + std::vector ArgT(1); + ArgT[0] = Type::IntTy; + + // now create full type of the add1 function: + FunctionType *Add1T = FunctionType::get(Type::IntTy, // type of result + ArgT, + /*not vararg*/false); + + // Now create the add1 function entry and + // insert this entry into module M + // (By passing a module as the last parameter to the Function constructor, + // it automatically gets appended to the Module.) + Add1F = new Function(Add1T, + Function::ExternalLinkage, // maybe too much + "add1", M); + + // Add a basic block to the function... (again, it automatically inserts + // because of the last argument.) + BasicBlock *BB = new BasicBlock("EntryBlock of add1 function", Add1F); + + // Get pointers to the constant `1'... + Value *One = ConstantSInt::get(Type::IntTy, 1); + + // Get pointers to the integer argument of the add1 function... + assert(Add1F->abegin() != Add1F->aend()); // Make sure there's an arg + Argument &ArgX = Add1F->afront(); // Get the arg + + // Create the add instruction... does not insert... + Instruction *Add = BinaryOperator::create(Instruction::Add, One, &ArgX, + "addresult"); + + // explicitly insert it into the basic block... + BB->getInstList().push_back(Add); + + // Create the return instruction and add it to the basic block + BB->getInstList().push_back(new ReturnInst(Add)); + + // function add1 is ready + } + + + // now we going to create function `foo': + Function *FooF; + + { + // Create the foo function type: + FunctionType *FooT = + FunctionType::get(Type::IntTy, // result has type: 'int ()' + std::vector(), // no arguments + /*not vararg*/false); + + // create the entry for function `foo' and insert + // this entry into module M: + FooF = + new Function(FooT, + Function::ExternalLinkage, // too wide? + "foo", M); + + // Add a basic block to the FooF function... + BasicBlock *BB = new BasicBlock("EntryBlock of add1 function", FooF); + + // Get pointers to the constant `10'... + Value *Ten = ConstantSInt::get(Type::IntTy, 10); + + // Put the argument Ten on stack and make call: + // ... + std::vector Params; + Params.push_back(Ten); + CallInst * Add1CallRes = new CallInst(Add1F, Params, "add1", BB); + + // Create the return instruction and add it to the basic block + BB->getInstList().push_back(new ReturnInst(Add1CallRes)); + + } + + // Now we going to create JIT ?? + ExistingModuleProvider* MP = new ExistingModuleProvider(M); + ExecutionEngine* EE = ExecutionEngine::create( MP, true ); + + // Call the `foo' function with no arguments: + std::vector noargs; + GenericValue gv = EE->runFunction(FooF, noargs); + + // import result of execution: + std::cout << "Result: " << gv.IntVal << std:: endl; + + return 0; +} From lattner at cs.uiuc.edu Thu Aug 12 12:56:13 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 12:56:13 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp SparcV9FrameInfo.h SparcV9PrologEpilogInserter.cpp Message-ID: <200408121756.MAA04484@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9BurgISel.cpp updated: 1.2 -> 1.3 SparcV9FrameInfo.h updated: 1.5 -> 1.6 SparcV9PrologEpilogInserter.cpp updated: 1.40 -> 1.41 --- Log message: When we want a constant, just use it, instead of calling through layers of virtual methods and register name mapping functions --- Diffs of the changes: (+10 -10) Index: llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp diff -u llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp:1.2 llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp:1.3 --- llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp:1.2 Wed Aug 4 03:05:27 2004 +++ llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp Thu Aug 12 12:56:00 2004 @@ -19,6 +19,8 @@ #include "SparcV9InstrForest.h" #include "SparcV9Internals.h" #include "SparcV9TmpInstr.h" +#include "SparcV9FrameInfo.h" +#include "SparcV9RegisterInfo.h" #include "llvm/CodeGen/IntrinsicLowering.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineFunction.h" @@ -2779,13 +2781,11 @@ assert(0 && "Unknown intrinsic function call should have been lowered!"); case Intrinsic::vastart: { // Get the address of the first incoming vararg argument on the stack - bool ignore; Function* func = cast(callInstr.getParent()->getParent()); int numFixedArgs = func->getFunctionType()->getNumParams(); - int fpReg = target.getFrameInfo()->getIncomingArgBaseRegNum(); - int argSize = target.getFrameInfo()->getSizeOfEachArgOnStack(); - int firstVarArgOff = numFixedArgs * argSize + target.getFrameInfo()-> - getFirstIncomingArgOffset(MachineFunction::get(func), ignore); + int fpReg = SparcV9::i6; + int firstVarArgOff = numFixedArgs * 8 + + SparcV9FrameInfo::FirstIncomingArgOffsetFromFP; mvec.push_back(BuildMI(V9::ADDi, 3).addMReg(fpReg).addSImm(firstVarArgOff). addRegDef(&callInstr)); return true; Index: llvm/lib/Target/SparcV9/SparcV9FrameInfo.h diff -u llvm/lib/Target/SparcV9/SparcV9FrameInfo.h:1.5 llvm/lib/Target/SparcV9/SparcV9FrameInfo.h:1.6 --- llvm/lib/Target/SparcV9/SparcV9FrameInfo.h:1.5 Wed Jun 2 00:54:42 2004 +++ llvm/lib/Target/SparcV9/SparcV9FrameInfo.h Thu Aug 12 12:56:00 2004 @@ -112,7 +112,6 @@ return growUp ? firstArg + relativeOffset : firstArg - relativeOffset; } -private: /*---------------------------------------------------------------------- This diagram shows the stack frame layout used by llc on SparcV9 V9. Note that only the location of automatic variables, spill area, Index: llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp diff -u llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.40 llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.41 --- llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.40 Mon Jul 19 02:52:35 2004 +++ llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp Thu Aug 12 12:56:01 2004 @@ -18,6 +18,8 @@ #include "SparcV9Internals.h" #include "SparcV9RegClassInfo.h" +#include "SparcV9RegisterInfo.h" +#include "SparcV9FrameInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineFunctionInfo.h" #include "llvm/CodeGen/MachineCodeForInstruction.h" @@ -123,13 +125,12 @@ int numArgRegs = TM.getRegInfo()->getNumOfIntArgRegs(); if (numFixedArgs < numArgRegs) { const TargetFrameInfo &FI = *TM.getFrameInfo(); - bool ignore; int firstArgReg = TM.getRegInfo()->getUnifiedRegNum( TM.getRegInfo()->getRegClassIDOfType(Type::IntTy), SparcV9IntRegClass::i0); - int fpReg = FI.getIncomingArgBaseRegNum(); - int argSize = FI.getSizeOfEachArgOnStack(); - int firstArgOffset= FI.getFirstIncomingArgOffset(MF,ignore); + int fpReg = SparcV9::i6; + int argSize = 8; + int firstArgOffset= SparcV9FrameInfo::FirstIncomingArgOffsetFromFP; int nextArgOffset = firstArgOffset + numFixedArgs * argSize; for (int i=numFixedArgs; i < numArgRegs; ++i) { From lattner at cs.uiuc.edu Thu Aug 12 12:58:17 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 12:58:17 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9FrameInfo.h Message-ID: <200408121758.MAA07945@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9FrameInfo.h updated: 1.6 -> 1.7 --- Log message: Remove dead methods --- Diffs of the changes: (+0 -23) Index: llvm/lib/Target/SparcV9/SparcV9FrameInfo.h diff -u llvm/lib/Target/SparcV9/SparcV9FrameInfo.h:1.6 llvm/lib/Target/SparcV9/SparcV9FrameInfo.h:1.7 --- llvm/lib/Target/SparcV9/SparcV9FrameInfo.h:1.6 Thu Aug 12 12:56:00 2004 +++ llvm/lib/Target/SparcV9/SparcV9FrameInfo.h Thu Aug 12 12:58:05 2004 @@ -67,29 +67,6 @@ int getTmpAreaOffset(MachineFunction& mcInfo, bool& growUp) const; int getDynamicAreaOffset(MachineFunction& mcInfo, bool& growUp) const; - // - // These methods specify the base register used for each stack area - // (generally FP or SP) - // - virtual int getIncomingArgBaseRegNum() const { - return (int) target.getRegInfo()->getFramePointer(); - } - virtual int getOutgoingArgBaseRegNum() const { - return (int) target.getRegInfo()->getStackPointer(); - } - virtual int getOptionalOutgoingArgBaseRegNum() const { - return (int) target.getRegInfo()->getStackPointer(); - } - virtual int getAutomaticVarBaseRegNum() const { - return (int) target.getRegInfo()->getFramePointer(); - } - virtual int getRegSpillAreaBaseRegNum() const { - return (int) target.getRegInfo()->getFramePointer(); - } - virtual int getDynamicAreaBaseRegNum() const { - return (int) target.getRegInfo()->getStackPointer(); - } - virtual int getIncomingArgOffset(MachineFunction& mcInfo, unsigned argNum) const { assert(argsOnStackHaveFixedSize()); From lattner at cs.uiuc.edu Thu Aug 12 12:58:26 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 12:58:26 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/TargetFrameInfo.cpp Message-ID: <200408121758.MAA08305@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target: TargetFrameInfo.cpp updated: 1.1 -> 1.2 --- Log message: Remove dead methods --- Diffs of the changes: (+0 -11) Index: llvm/lib/Target/TargetFrameInfo.cpp diff -u llvm/lib/Target/TargetFrameInfo.cpp:1.1 llvm/lib/Target/TargetFrameInfo.cpp:1.2 --- llvm/lib/Target/TargetFrameInfo.cpp:1.1 Thu Mar 11 17:52:43 2004 +++ llvm/lib/Target/TargetFrameInfo.cpp Thu Aug 12 12:58:16 2004 @@ -73,14 +73,3 @@ TargetFrameInfo::getDynamicAreaOffset(MachineFunction& mcInfo, bool& growUp) const { abort(); } -// -// These methods specify the base register used for each stack area -// (generally FP or SP) -// -int TargetFrameInfo::getIncomingArgBaseRegNum() const { abort(); } -int TargetFrameInfo::getOutgoingArgBaseRegNum() const { abort(); } -int TargetFrameInfo::getOptionalOutgoingArgBaseRegNum() const {abort();} -int TargetFrameInfo::getAutomaticVarBaseRegNum() const { abort(); } -int TargetFrameInfo::getRegSpillAreaBaseRegNum() const { abort(); } -int TargetFrameInfo::getDynamicAreaBaseRegNum() const { abort(); } - From lattner at cs.uiuc.edu Thu Aug 12 12:58:39 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 12:58:39 -0500 Subject: [llvm-commits] CVS: llvm/include/llvm/Target/TargetFrameInfo.h Message-ID: <200408121758.MAA08569@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/Target: TargetFrameInfo.h updated: 1.12 -> 1.13 --- Log message: Remove dead methods --- Diffs of the changes: (+0 -11) Index: llvm/include/llvm/Target/TargetFrameInfo.h diff -u llvm/include/llvm/Target/TargetFrameInfo.h:1.12 llvm/include/llvm/Target/TargetFrameInfo.h:1.13 --- llvm/include/llvm/Target/TargetFrameInfo.h:1.12 Tue Jun 8 01:23:17 2004 +++ llvm/include/llvm/Target/TargetFrameInfo.h Thu Aug 12 12:58:27 2004 @@ -95,17 +95,6 @@ bool& growUp) const; virtual int getDynamicAreaOffset (MachineFunction& mcInfo, bool& growUp) const; - - // - // These methods specify the base register used for each stack area - // (generally FP or SP) - // - virtual int getIncomingArgBaseRegNum() const; - virtual int getOutgoingArgBaseRegNum() const; - virtual int getOptionalOutgoingArgBaseRegNum() const; - virtual int getAutomaticVarBaseRegNum() const; - virtual int getRegSpillAreaBaseRegNum() const; - virtual int getDynamicAreaBaseRegNum() const; }; } // End llvm namespace From lattner at cs.uiuc.edu Thu Aug 12 13:06:47 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 13:06:47 -0500 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/MachineFunction.cpp Message-ID: <200408121806.NAA20556@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: MachineFunction.cpp updated: 1.65 -> 1.66 --- Log message: The only target that uses this code (v9) always has argsOnStackHaveFixedSize set to true (obviously) --- Diffs of the changes: (+1 -16) Index: llvm/lib/CodeGen/MachineFunction.cpp diff -u llvm/lib/CodeGen/MachineFunction.cpp:1.65 llvm/lib/CodeGen/MachineFunction.cpp:1.66 --- llvm/lib/CodeGen/MachineFunction.cpp:1.65 Thu Jul 29 12:20:54 2004 +++ llvm/lib/CodeGen/MachineFunction.cpp Thu Aug 12 13:06:35 2004 @@ -332,22 +332,7 @@ if (numExtra <= 0) continue; - unsigned sizeForThisCall; - if (frameInfo.argsOnStackHaveFixedSize()) - { - int argSize = frameInfo.getSizeOfEachArgOnStack(); - sizeForThisCall = numExtra * (unsigned) argSize; - } - else - { - assert(0 && "UNTESTED CODE: Size per stack argument is not " - "fixed on this architecture: use actual arg sizes to " - "compute MaxOptionalArgsSize"); - sizeForThisCall = 0; - for (unsigned i = 0; i < numOperands; ++i) - sizeForThisCall += target.getTargetData().getTypeSize(callInst-> - getOperand(i)->getType()); - } + unsigned sizeForThisCall = numExtra * 8; if (maxSize < sizeForThisCall) maxSize = sizeForThisCall; From lattner at cs.uiuc.edu Thu Aug 12 13:10:30 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 13:10:30 -0500 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/MachineFunction.cpp Message-ID: <200408121810.NAA23020@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: MachineFunction.cpp updated: 1.66 -> 1.67 --- Log message: Forward substitute some constants into their users --- Diffs of the changes: (+2 -5) Index: llvm/lib/CodeGen/MachineFunction.cpp diff -u llvm/lib/CodeGen/MachineFunction.cpp:1.66 llvm/lib/CodeGen/MachineFunction.cpp:1.67 --- llvm/lib/CodeGen/MachineFunction.cpp:1.66 Thu Aug 12 13:06:35 2004 +++ llvm/lib/CodeGen/MachineFunction.cpp Thu Aug 12 13:10:18 2004 @@ -319,8 +319,6 @@ ComputeMaxOptionalArgsSize(const TargetMachine& target, const Function *F, unsigned &maxOptionalNumArgs) { - const TargetFrameInfo &frameInfo = *target.getFrameInfo(); - unsigned maxSize = 0; for (Function::const_iterator BB = F->begin(), BBE = F->end(); BB !=BBE; ++BB) @@ -328,7 +326,7 @@ if (const CallInst *callInst = dyn_cast(I)) { unsigned numOperands = callInst->getNumOperands() - 1; - int numExtra = (int)numOperands-frameInfo.getNumFixedOutgoingArgs(); + int numExtra = numOperands-6; if (numExtra <= 0) continue; @@ -370,8 +368,7 @@ maxOptionalArgsSize = ComputeMaxOptionalArgsSize(MF.getTarget(), MF.getFunction(), maxOptionalNumArgs); - staticStackSize = maxOptionalArgsSize - + MF.getTarget().getFrameInfo()->getMinStackFrameSize(); + staticStackSize = maxOptionalArgsSize + 176; } int From lattner at cs.uiuc.edu Thu Aug 12 13:21:07 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 13:21:07 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp Message-ID: <200408121821.NAA30351@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9PrologEpilogInserter.cpp updated: 1.41 -> 1.42 --- Log message: Virtual method calls are overrated --- Diffs of the changes: (+3 -3) Index: llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp diff -u llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.41 llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.42 --- llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.41 Thu Aug 12 12:56:01 2004 +++ llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp Thu Aug 12 13:20:55 2004 @@ -60,9 +60,9 @@ if (staticStackSize < (unsigned) frameInfo.getMinStackFrameSize()) staticStackSize = (unsigned) frameInfo.getMinStackFrameSize(); - if (unsigned padsz = (staticStackSize % - (unsigned) frameInfo.getStackFrameSizeAlignment())) - staticStackSize += frameInfo.getStackFrameSizeAlignment() - padsz; + if (unsigned padsz = staticStackSize % + SparcV9FrameInfo::StackFrameSizeAlignment) + staticStackSize += SparcV9FrameInfo::StackFrameSizeAlignment - padsz; return staticStackSize; } From lattner at cs.uiuc.edu Thu Aug 12 13:21:22 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 13:21:22 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp SparcV9FrameInfo.cpp Message-ID: <200408121821.NAA31735@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9BurgISel.cpp updated: 1.3 -> 1.4 SparcV9FrameInfo.cpp updated: 1.3 -> 1.4 --- Log message: Virtual method calls are overrated. --- Diffs of the changes: (+6 -8) Index: llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp diff -u llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp:1.3 llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp:1.4 --- llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp:1.3 Thu Aug 12 12:56:00 2004 +++ llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp Thu Aug 12 13:20:41 2004 @@ -2494,8 +2494,8 @@ numElementsVal->getType(), isValid); assert(isValid && "Unexpectedly large array dimension in alloca!"); int64_t total = numElem * tsize; - if (int extra= total % target.getFrameInfo()->getStackFrameSizeAlignment()) - total += target.getFrameInfo()->getStackFrameSizeAlignment() - extra; + if (int extra= total % SparcV9FrameInfo::StackFrameSizeAlignment) + total += SparcV9FrameInfo::StackFrameSizeAlignment - extra; totalSizeVal = ConstantSInt::get(Type::IntTy, total); } else { // The size is not a constant. Generate code to compute it and Index: llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp diff -u llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp:1.3 llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp:1.4 --- llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp:1.3 Sun Apr 25 02:04:49 2004 +++ llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp Thu Aug 12 13:20:41 2004 @@ -7,9 +7,7 @@ // //===----------------------------------------------------------------------===// // -// Interface to stack frame layout info for the UltraSPARC. Starting offsets -// for each area of the stack frame are aligned at a multiple of -// getStackFrameSizeAlignment(). +// Interface to stack frame layout info for the UltraSPARC. // //===----------------------------------------------------------------------===// @@ -57,9 +55,9 @@ // dynamic-size alloca. pos = false; unsigned optArgsSize = mcInfo.getInfo()->getMaxOptionalArgsSize(); - if (int extra = optArgsSize % getStackFrameSizeAlignment()) - optArgsSize += (getStackFrameSizeAlignment() - extra); + if (int extra = optArgsSize % 16) + optArgsSize += (16 - extra); int offset = optArgsSize + FirstOptionalOutgoingArgOffsetFromSP; - assert((offset - OFFSET) % getStackFrameSizeAlignment() == 0); + assert((offset - OFFSET) % 16 == 0); return offset; } From lattner at cs.uiuc.edu Thu Aug 12 13:29:18 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 13:29:18 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9RegInfo.cpp SparcV9PrologEpilogInserter.cpp SparcV9BurgISel.cpp Message-ID: <200408121829.NAA09515@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9RegInfo.cpp updated: 1.133 -> 1.134 SparcV9PrologEpilogInserter.cpp updated: 1.42 -> 1.43 SparcV9BurgISel.cpp updated: 1.4 -> 1.5 --- Log message: Instead of a virtual method call, lets try a direct constant reference --- Diffs of the changes: (+8 -7) Index: llvm/lib/Target/SparcV9/SparcV9RegInfo.cpp diff -u llvm/lib/Target/SparcV9/SparcV9RegInfo.cpp:1.133 llvm/lib/Target/SparcV9/SparcV9RegInfo.cpp:1.134 --- llvm/lib/Target/SparcV9/SparcV9RegInfo.cpp:1.133 Wed Aug 4 02:29:53 2004 +++ llvm/lib/Target/SparcV9/SparcV9RegInfo.cpp Thu Aug 12 13:29:05 2004 @@ -25,6 +25,7 @@ #include "SparcV9Internals.h" #include "SparcV9RegClassInfo.h" #include "SparcV9RegInfo.h" +#include "SparcV9FrameInfo.h" #include "SparcV9TargetMachine.h" #include "SparcV9TmpInstr.h" #include @@ -492,7 +493,7 @@ // a full double-word so the offset does not need to be adjusted. if (regType == FPSingleRegType) { unsigned argSize = target.getTargetData().getTypeSize(LR->getType()); - unsigned slotSize = frameInfo.getSizeOfEachArgOnStack(); + unsigned slotSize = SparcV9FrameInfo::SizeOfEachArgOnStack; assert(argSize <= slotSize && "Insufficient slot size!"); offsetFromFP += slotSize - argSize; } @@ -550,7 +551,7 @@ // a full double-word so the offset does not need to be adjusted. if (regType == FPSingleRegType) { unsigned argSize = target.getTargetData().getTypeSize(LR->getType()); - unsigned slotSize = frameInfo.getSizeOfEachArgOnStack(); + unsigned slotSize = SparcV9FrameInfo::SizeOfEachArgOnStack; assert(argSize <= slotSize && "Insufficient slot size!"); offsetFromFP += slotSize - argSize; } Index: llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp diff -u llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.42 llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.43 --- llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.42 Thu Aug 12 13:20:55 2004 +++ llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp Thu Aug 12 13:29:05 2004 @@ -58,8 +58,8 @@ unsigned staticStackSize = MF.getInfo()->getStaticStackSize(); - if (staticStackSize < (unsigned) frameInfo.getMinStackFrameSize()) - staticStackSize = (unsigned) frameInfo.getMinStackFrameSize(); + if (staticStackSize < SparcV9FrameInfo::MinStackFrameSize) + staticStackSize = SparcV9FrameInfo::MinStackFrameSize; if (unsigned padsz = staticStackSize % SparcV9FrameInfo::StackFrameSizeAlignment) staticStackSize += SparcV9FrameInfo::StackFrameSizeAlignment - padsz; Index: llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp diff -u llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp:1.4 llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp:1.5 --- llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp:1.4 Thu Aug 12 13:20:41 2004 +++ llvm/lib/Target/SparcV9/SparcV9BurgISel.cpp Thu Aug 12 13:29:05 2004 @@ -2575,7 +2575,7 @@ paddedSize, tsize * numElements); - if (((int)paddedSize) > 8 * target.getFrameInfo()->getSizeOfEachArgOnStack()|| + if (((int)paddedSize) > 8 * SparcV9FrameInfo::SizeOfEachArgOnStack || !target.getInstrInfo()->constantFitsInImmedField(V9::LDXi,offsetFromFP)) { CreateCodeForVariableSizeAlloca(target, result, tsize, ConstantSInt::get(Type::IntTy,numElements), @@ -3992,7 +3992,7 @@ // not need to be adjusted. int argOffset = frameInfo.getOutgoingArgOffset(MF, argNo); if (argType->isFloatingPoint()) { - unsigned slotSize = frameInfo.getSizeOfEachArgOnStack(); + unsigned slotSize = SparcV9FrameInfo::SizeOfEachArgOnStack; assert(argSize <= slotSize && "Insufficient slot size!"); argOffset += slotSize - argSize; } @@ -4132,7 +4132,7 @@ Instruction* vaNextI = subtreeRoot->getInstruction(); assert(target.getTargetData().getTypeSize(vaNextI->getType()) <= 8 && "We assumed that all LLVM parameter types <= 8 bytes!"); - int argSize = target.getFrameInfo()->getSizeOfEachArgOnStack(); + unsigned argSize = SparcV9FrameInfo::SizeOfEachArgOnStack; mvec.push_back(BuildMI(V9::ADDi, 3).addReg(vaNextI->getOperand(0)). addSImm(argSize).addRegDef(vaNextI)); break; From lattner at cs.uiuc.edu Thu Aug 12 13:36:41 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 13:36:41 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp Message-ID: <200408121836.NAA17436@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9PrologEpilogInserter.cpp updated: 1.43 -> 1.44 --- Log message: Fix warning --- Diffs of the changes: (+1 -1) Index: llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp diff -u llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.43 llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.44 --- llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp:1.43 Thu Aug 12 13:29:05 2004 +++ llvm/lib/Target/SparcV9/SparcV9PrologEpilogInserter.cpp Thu Aug 12 13:36:28 2004 @@ -58,7 +58,7 @@ unsigned staticStackSize = MF.getInfo()->getStaticStackSize(); - if (staticStackSize < SparcV9FrameInfo::MinStackFrameSize) + if (staticStackSize < (unsigned)SparcV9FrameInfo::MinStackFrameSize) staticStackSize = SparcV9FrameInfo::MinStackFrameSize; if (unsigned padsz = staticStackSize % SparcV9FrameInfo::StackFrameSizeAlignment) From lattner at cs.uiuc.edu Thu Aug 12 13:37:06 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 13:37:06 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp SparcV9FrameInfo.h Message-ID: <200408121837.NAA17689@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target/SparcV9: SparcV9FrameInfo.cpp updated: 1.4 -> 1.5 SparcV9FrameInfo.h updated: 1.7 -> 1.8 --- Log message: Remove dead methods --- Diffs of the changes: (+7 -46) Index: llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp diff -u llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp:1.4 llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp:1.5 --- llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp:1.4 Thu Aug 12 13:20:41 2004 +++ llvm/lib/Target/SparcV9/SparcV9FrameInfo.cpp Thu Aug 12 13:36:53 2004 @@ -19,12 +19,6 @@ using namespace llvm; int -SparcV9FrameInfo::getFirstAutomaticVarOffset(MachineFunction&, bool& pos) const { - pos = false; // static stack area grows downwards - return StaticAreaOffsetFromFP; -} - -int SparcV9FrameInfo::getRegSpillAreaOffset(MachineFunction& mcInfo, bool& pos) const { // ensure no more auto vars are added Index: llvm/lib/Target/SparcV9/SparcV9FrameInfo.h diff -u llvm/lib/Target/SparcV9/SparcV9FrameInfo.h:1.7 llvm/lib/Target/SparcV9/SparcV9FrameInfo.h:1.8 --- llvm/lib/Target/SparcV9/SparcV9FrameInfo.h:1.7 Thu Aug 12 12:58:05 2004 +++ llvm/lib/Target/SparcV9/SparcV9FrameInfo.h Thu Aug 12 13:36:53 2004 @@ -8,8 +8,6 @@ //===----------------------------------------------------------------------===// // // Interface to stack frame layout info for the UltraSPARC. -// Starting offsets for each area of the stack frame are aligned at -// a multiple of getStackFrameSizeAlignment(). // //---------------------------------------------------------------------------- @@ -28,15 +26,6 @@ SparcV9FrameInfo(const TargetMachine &TM) : TargetFrameInfo(StackGrowsDown, StackFrameSizeAlignment, 0), target(TM) {} -public: - // These methods provide constant parameters of the frame layout. - // - int getStackFrameSizeAlignment() const { return StackFrameSizeAlignment;} - int getMinStackFrameSize() const { return MinStackFrameSize; } - int getNumFixedOutgoingArgs() const { return NumFixedOutgoingArgs; } - int getSizeOfEachArgOnStack() const { return SizeOfEachArgOnStack; } - bool argsOnStackHaveFixedSize() const { return true; } - // This method adjusts a stack offset to meet alignment rules of target. // The fixed OFFSET (0x7ff) must be subtracted and the result aligned. virtual int adjustAlignment(int unalignedOffset, bool growUp, @@ -48,45 +37,24 @@ // particular function. The frame contents are obtained from the // MachineCodeInfoForMethod object for the given function. // - int getFirstIncomingArgOffset(MachineFunction& mcInfo, bool& growUp) const { - growUp = true; // arguments area grows upwards - return FirstIncomingArgOffsetFromFP; - } - int getFirstOutgoingArgOffset(MachineFunction& mcInfo, bool& growUp) const { - growUp = true; // arguments area grows upwards - return FirstOutgoingArgOffsetFromSP; + int getFirstAutomaticVarOffset(MachineFunction& mcInfo, bool& growUp) const { + growUp = false; + return StaticAreaOffsetFromFP; } - int getFirstOptionalOutgoingArgOffset(MachineFunction& mcInfo, - bool& growUp) const { - growUp = true; // arguments area grows upwards - return FirstOptionalOutgoingArgOffsetFromSP; - } - - int getFirstAutomaticVarOffset(MachineFunction& mcInfo, bool& growUp) const; int getRegSpillAreaOffset(MachineFunction& mcInfo, bool& growUp) const; int getTmpAreaOffset(MachineFunction& mcInfo, bool& growUp) const; int getDynamicAreaOffset(MachineFunction& mcInfo, bool& growUp) const; virtual int getIncomingArgOffset(MachineFunction& mcInfo, unsigned argNum) const { - assert(argsOnStackHaveFixedSize()); - - unsigned relativeOffset = argNum * getSizeOfEachArgOnStack(); - bool growUp; // do args grow up or down - int firstArg = getFirstIncomingArgOffset(mcInfo, growUp); - return growUp ? firstArg + relativeOffset : firstArg - relativeOffset; + unsigned relativeOffset = argNum * SizeOfEachArgOnStack; + int firstArg = FirstIncomingArgOffsetFromFP; + return firstArg + relativeOffset; } virtual int getOutgoingArgOffset(MachineFunction& mcInfo, unsigned argNum) const { - assert(argsOnStackHaveFixedSize()); - //assert(((int) argNum - this->getNumFixedOutgoingArgs()) - // <= (int) mcInfo.getInfo()->getMaxOptionalNumArgs()); - - unsigned relativeOffset = argNum * getSizeOfEachArgOnStack(); - bool growUp; // do args grow up or down - int firstArg = getFirstOutgoingArgOffset(mcInfo, growUp); - return growUp ? firstArg + relativeOffset : firstArg - relativeOffset; + return FirstOutgoingArgOffsetFromSP + argNum * SizeOfEachArgOnStack; } /*---------------------------------------------------------------------- @@ -136,7 +104,6 @@ static const int OFFSET = (int) 0x7ff; static const int StackFrameSizeAlignment = 16; static const int MinStackFrameSize = 176; - static const int NumFixedOutgoingArgs = 6; static const int SizeOfEachArgOnStack = 8; static const int FirstIncomingArgOffsetFromFP = 128 + OFFSET; static const int FirstOptionalIncomingArgOffsetFromFP = 176 + OFFSET; From lattner at cs.uiuc.edu Thu Aug 12 13:37:16 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 13:37:16 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/TargetFrameInfo.cpp Message-ID: <200408121837.NAA17972@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Target: TargetFrameInfo.cpp updated: 1.2 -> 1.3 --- Log message: Remove dead methods --- Diffs of the changes: (+0 -18) Index: llvm/lib/Target/TargetFrameInfo.cpp diff -u llvm/lib/Target/TargetFrameInfo.cpp:1.2 llvm/lib/Target/TargetFrameInfo.cpp:1.3 --- llvm/lib/Target/TargetFrameInfo.cpp:1.2 Thu Aug 12 12:58:16 2004 +++ llvm/lib/Target/TargetFrameInfo.cpp Thu Aug 12 13:37:04 2004 @@ -21,12 +21,6 @@ // are Sparc specific. //===--------------------------------------------------------------------===// -int TargetFrameInfo::getStackFrameSizeAlignment() const { abort(); } -int TargetFrameInfo::getMinStackFrameSize() const { abort(); } -int TargetFrameInfo::getNumFixedOutgoingArgs() const { abort(); } -int TargetFrameInfo::getSizeOfEachArgOnStack() const { abort(); } -bool TargetFrameInfo::argsOnStackHaveFixedSize() const { abort(); } - // This method adjusts a stack offset to meet alignment rules of target. int TargetFrameInfo::adjustAlignment(int unalignedOffset, bool growUp, @@ -46,18 +40,6 @@ unsigned argNum) const { abort(); } int -TargetFrameInfo::getFirstIncomingArgOffset(MachineFunction& mcInfo, - bool& growUp) const { abort(); } - -int -TargetFrameInfo::getFirstOutgoingArgOffset(MachineFunction& mcInfo, - bool& growUp) const { abort(); } - -int -TargetFrameInfo::getFirstOptionalOutgoingArgOffset(MachineFunction&, - bool& growUp) const { abort(); } - -int TargetFrameInfo::getFirstAutomaticVarOffset(MachineFunction& mcInfo, bool& growUp) const { abort(); } From lattner at cs.uiuc.edu Thu Aug 12 13:37:27 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 13:37:27 -0500 Subject: [llvm-commits] CVS: llvm/include/llvm/Target/TargetFrameInfo.h Message-ID: <200408121837.NAA18238@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/Target: TargetFrameInfo.h updated: 1.13 -> 1.14 --- Log message: Remove dead methods --- Diffs of the changes: (+0 -12) Index: llvm/include/llvm/Target/TargetFrameInfo.h diff -u llvm/include/llvm/Target/TargetFrameInfo.h:1.13 llvm/include/llvm/Target/TargetFrameInfo.h:1.14 --- llvm/include/llvm/Target/TargetFrameInfo.h:1.13 Thu Aug 12 12:58:27 2004 +++ llvm/include/llvm/Target/TargetFrameInfo.h Thu Aug 12 13:37:15 2004 @@ -61,12 +61,6 @@ // are Sparc specific. //===--------------------------------------------------------------------===// - virtual int getStackFrameSizeAlignment () const; - virtual int getMinStackFrameSize () const; - virtual int getNumFixedOutgoingArgs () const; - virtual int getSizeOfEachArgOnStack () const; - virtual bool argsOnStackHaveFixedSize () const; - // This method adjusts a stack offset to meet alignment rules of target. virtual int adjustAlignment(int unalignedOffset, bool growUp, unsigned align) const; @@ -81,12 +75,6 @@ virtual int getOutgoingArgOffset (MachineFunction& mcInfo, unsigned argNum) const; - virtual int getFirstIncomingArgOffset (MachineFunction& mcInfo, - bool& growUp) const; - virtual int getFirstOutgoingArgOffset (MachineFunction& mcInfo, - bool& growUp) const; - virtual int getFirstOptionalOutgoingArgOffset (MachineFunction&, - bool& growUp) const; virtual int getFirstAutomaticVarOffset (MachineFunction& mcInfo, bool& growUp) const; virtual int getRegSpillAreaOffset (MachineFunction& mcInfo, From criswell at cs.uiuc.edu Thu Aug 12 13:49:36 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Thu, 12 Aug 2004 13:49:36 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/test/Programs/SingleSource/Regression/C/2004-08-12-InlinerAndAllocas.c Message-ID: <200408121849.NAA07977@choi.cs.uiuc.edu> Changes in directory llvm/test/Programs/SingleSource/Regression/C: 2004-08-12-InlinerAndAllocas.c added (r1.1.2.1) --- Log message: Regression test for a bug that broken 176.gcc. --- Diffs of the changes: (+21 -0) Index: llvm/test/Programs/SingleSource/Regression/C/2004-08-12-InlinerAndAllocas.c diff -c /dev/null llvm/test/Programs/SingleSource/Regression/C/2004-08-12-InlinerAndAllocas.c:1.1.2.1 *** /dev/null Thu Aug 12 13:49:34 2004 --- llvm/test/Programs/SingleSource/Regression/C/2004-08-12-InlinerAndAllocas.c Thu Aug 12 13:49:23 2004 *************** *** 0 **** --- 1,21 ---- + // A compiler cannot inline Callee into main unless it is prepared to reclaim + // the stack memory allocated in it. + + #include + #include + + static int Callee(int i) { + if (i != 0) { + char *X = alloca(1000); + sprintf(X, "%d\n", i); + return X[0]; + } + return 0; + } + + int main() { + int i, j = 0; + for (i = 0; i < 10000; ++i) + j += Callee(i); + printf("%d\n", j); + } From lattner at cs.uiuc.edu Thu Aug 12 14:01:27 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 14:01:27 -0500 Subject: [llvm-commits] CVS: llvm/lib/CodeGen/PrologEpilogInserter.cpp Message-ID: <200408121901.OAA26078@apoc.cs.uiuc.edu> Changes in directory llvm/lib/CodeGen: PrologEpilogInserter.cpp updated: 1.27 -> 1.28 --- Log message: Split saveCallerSavedRegisters into two methods for clarity, and add comments. Add support for targets that must spill certain physregs at certain locations. Patch contributed by Nate Begeman, slightly hacked by me. --- Diffs of the changes: (+52 -9) Index: llvm/lib/CodeGen/PrologEpilogInserter.cpp diff -u llvm/lib/CodeGen/PrologEpilogInserter.cpp:1.27 llvm/lib/CodeGen/PrologEpilogInserter.cpp:1.28 --- llvm/lib/CodeGen/PrologEpilogInserter.cpp:1.27 Sat Aug 7 02:18:41 2004 +++ llvm/lib/CodeGen/PrologEpilogInserter.cpp Thu Aug 12 14:01:14 2004 @@ -40,6 +40,9 @@ // code for any caller saved registers that are modified. Also calculate // the MaxCallFrameSize and HasCalls variables for the function's frame // information and eliminates call frame pseudo instructions. + calculateCallerSavedRegisters(Fn); + + // Add the code to save and restore the caller saved registers saveCallerSavedRegisters(Fn); // Allow the target machine to make final modifications to the function @@ -49,17 +52,28 @@ // Calculate actual frame offsets for all of the abstract stack objects... calculateFrameObjectOffsets(Fn); - // Add prolog and epilog code to the function. + // Add prolog and epilog code to the function. This function is required + // to align the stack frame as necessary for any stack variables or + // called functions. Because of this, calculateCallerSavedRegisters + // must be called before this function in order to set the HasCalls + // and MaxCallFrameSize variables. insertPrologEpilogCode(Fn); // Replace all MO_FrameIndex operands with physical register references // and actual offsets. // replaceFrameIndices(Fn); + + RegsToSave.clear(); + StackSlots.clear(); return true; } private: + std::vector RegsToSave; + std::vector StackSlots; + + void calculateCallerSavedRegisters(MachineFunction &Fn); void saveCallerSavedRegisters(MachineFunction &Fn); void calculateFrameObjectOffsets(MachineFunction &Fn); void replaceFrameIndices(MachineFunction &Fn); @@ -74,15 +88,14 @@ FunctionPass *llvm::createPrologEpilogCodeInserter() { return new PEI(); } -/// saveCallerSavedRegisters - Scan the function for modified caller saved -/// registers and insert spill code for any caller saved registers that are -/// modified. Also calculate the MaxCallFrameSize and HasCalls variables for +/// calculateCallerSavedRegisters - Scan the function for modified caller saved +/// registers. Also calculate the MaxCallFrameSize and HasCalls variables for /// the function's frame information and eliminates call frame pseudo /// instructions. /// -void PEI::saveCallerSavedRegisters(MachineFunction &Fn) { +void PEI::calculateCallerSavedRegisters(MachineFunction &Fn) { const MRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo(); - const TargetFrameInfo &FrameInfo = *Fn.getTarget().getFrameInfo(); + const TargetFrameInfo *TFI = Fn.getTarget().getFrameInfo(); // Get the callee saved register list... const unsigned *CSRegs = RegInfo->getCalleeSaveRegs(); @@ -131,7 +144,6 @@ // Now figure out which *callee saved* registers are modified by the current // function, thus needing to be saved and restored in the prolog/epilog. // - std::vector RegsToSave; for (unsigned i = 0; CSRegs[i]; ++i) { unsigned Reg = CSRegs[i]; if (ModifiedRegs[Reg]) { @@ -150,13 +162,44 @@ if (RegsToSave.empty()) return; // Early exit if no caller saved registers are modified! + unsigned NumFixedSpillSlots; + std::pair *FixedSpillSlots = + TFI->getCalleeSaveSpillSlots(NumFixedSpillSlots); + // Now that we know which registers need to be saved and restored, allocate // stack slots for them. - std::vector StackSlots; for (unsigned i = 0, e = RegsToSave.size(); i != e; ++i) { - int FrameIdx = FFI->CreateStackObject(RegInfo->getRegClass(RegsToSave[i])); + unsigned Reg = RegsToSave[i]; + int FrameIdx; + const TargetRegisterClass *RC = RegInfo->getRegClass(Reg); + + // Check to see if this physreg must be spilled to a particular stack slot + // on this target. + std::pair *FixedSlot = FixedSpillSlots; + while (FixedSlot != FixedSpillSlots+NumFixedSpillSlots && + FixedSlot->first != Reg) + ++FixedSlot; + + if (FixedSlot == FixedSpillSlots+NumFixedSpillSlots) { + // Nope, just spill it anywhere convenient. + FrameIdx = FFI->CreateStackObject(RC); + } else { + // Spill it to the stack where we must. + FrameIdx = FFI->CreateFixedObject(RC->getSize(), FixedSlot->second); + } StackSlots.push_back(FrameIdx); } +} + +/// saveCallerSavedRegisters - Insert spill code for any caller saved registers +/// that are modified in the function. +/// +void PEI::saveCallerSavedRegisters(MachineFunction &Fn) { + // Early exit if no caller saved registers are modified! + if (RegsToSave.empty()) + return; + + const MRegisterInfo *RegInfo = Fn.getTarget().getRegisterInfo(); // Now that we have a stack slot for each register to be saved, insert spill // code into the entry block... From lattner at cs.uiuc.edu Thu Aug 12 14:02:05 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 14:02:05 -0500 Subject: [llvm-commits] CVS: llvm/include/llvm/Target/TargetFrameInfo.h Message-ID: <200408121902.OAA26200@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/Target: TargetFrameInfo.h updated: 1.14 -> 1.15 --- Log message: Allow targets to specify particular stack slots that certain physregs must be spilled into. --- Diffs of the changes: (+17 -0) Index: llvm/include/llvm/Target/TargetFrameInfo.h diff -u llvm/include/llvm/Target/TargetFrameInfo.h:1.14 llvm/include/llvm/Target/TargetFrameInfo.h:1.15 --- llvm/include/llvm/Target/TargetFrameInfo.h:1.14 Thu Aug 12 13:37:15 2004 +++ llvm/include/llvm/Target/TargetFrameInfo.h Thu Aug 12 14:01:55 2004 @@ -14,6 +14,8 @@ #ifndef LLVM_TARGET_TARGETFRAMEINFO_H #define LLVM_TARGET_TARGETFRAMEINFO_H +#include + namespace llvm { class MachineFunction; @@ -56,6 +58,21 @@ /// int getOffsetOfLocalArea() const { return LocalAreaOffset; } + /// getCalleeSaveSpillSlots - This method returns a pointer to an array of + /// pairs, that contains an entry for each callee save register that must be + /// spilled to a particular stack location if it is spilled. + /// + /// Each entry in this array contains a pair, indicating the + /// fixed offset from the incoming stack pointer that each register should be + /// spilled at. If a register is not listed here, the code generator is + /// allowed to spill it anywhere it chooses. + /// + virtual std::pair * + getCalleeSaveSpillSlots(unsigned &NumEntries) const { + NumEntries = 0; + return 0; + } + //===--------------------------------------------------------------------===// // These methods provide details of the stack frame used by Sparc, thus they // are Sparc specific. From lattner at cs.uiuc.edu Thu Aug 12 14:06:36 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 14:06:36 -0500 Subject: [llvm-commits] CVS: llvm/docs/ExtendingLLVM.html Message-ID: <200408121906.OAA26246@apoc.cs.uiuc.edu> Changes in directory llvm/docs: ExtendingLLVM.html updated: 1.9 -> 1.10 --- Log message: Add information on adding a derived type to LLVM, patch contributed by Brad Jones! --- Diffs of the changes: (+42 -2) Index: llvm/docs/ExtendingLLVM.html diff -u llvm/docs/ExtendingLLVM.html:1.9 llvm/docs/ExtendingLLVM.html:1.10 --- llvm/docs/ExtendingLLVM.html:1.9 Thu Jul 29 12:31:57 2004 +++ llvm/docs/ExtendingLLVM.html Thu Aug 12 14:06:24 2004 @@ -215,7 +215,47 @@
        -

        TODO

        +
          +
        1. llvm/include/llvm/Type.def: + add enum for the type
        2. + +
        3. llvm/include/llvm/Type.h: + add ID number for the new type; add a forward declaration of the type also
        4. + +
        5. llvm/include/llvm/DerivedType.h: + add new class to represent new class in the hierarchy; add forward + declaration to the TypeMap value type
        6. + +
        7. llvm/lib/VMCore/Type.cpp: + add support for derived type to: + std::string getTypeDescription(const Type &Ty, + std::vector &TypeStack) + bool TypesEqual(const Type* Ty, const Type *Ty2, + std::map & EqTypes) + add necessary member functions for type, and factory + methods
        8. + +
        9. llvm/lib/AsmReader/Lexer.l: + add ability to parse in the type from text assembly
        10. + +
        11. llvm/lib/ByteCode/Writer/Writer.cpp: + modify void BytecodeWriter::outputType(const Type *T) to + serialize your type
        12. + +
        13. llvm/lib/ByteCode/Reader/Reader.cpp: + modify const Type *BytecodeReader::ParseType() to + read your data type
        14. + +
        15. llvm/lib/VMCore/AsmWriter.cpp: + modify void calcTypeName(const Type *Ty, + std::vector &TypeStack, + std::map &TypeNames, + std::string & Result) + to output the new derived type +
        16. + + +
        @@ -231,7 +271,7 @@ Misha Brukman
        The LLVM Compiler Infrastructure
        - Last modified: $Date: 2004/07/29 17:31:57 $ + Last modified: $Date: 2004/08/12 19:06:24 $ From lattner at cs.uiuc.edu Thu Aug 12 14:12:40 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 14:12:40 -0500 Subject: [llvm-commits] CVS: llvm/docs/LangRef.html Message-ID: <200408121912.OAA26282@apoc.cs.uiuc.edu> Changes in directory llvm/docs: LangRef.html updated: 1.71 -> 1.72 --- Log message: Add description of packed type support. Patch contributed by Brad Jones! --- Diffs of the changes: (+40 -22) Index: llvm/docs/LangRef.html diff -u llvm/docs/LangRef.html:1.71 llvm/docs/LangRef.html:1.72 --- llvm/docs/LangRef.html:1.71 Fri Jul 2 16:08:14 2004 +++ llvm/docs/LangRef.html Thu Aug 12 14:12:28 2004 @@ -26,7 +26,7 @@
      • Function Type
      • Pointer Type
      • Structure Type
      • - +
      • Packed Type
      • @@ -398,7 +398,7 @@ first class bool, ubyte, sbyte, ushort, short,
        -uint, int, ulong, long, float, double, pointer
        +uint, int, ulong, long, float, double, pointer, packed @@ -555,22 +555,29 @@ - - - +
        - -Mention/decide that packed types work with saturation or not. Maybe have a packed+saturated type in addition to just a packed type.

        - -Packed types should be 'nonsaturated' because standard data types are not saturated. Maybe have a saturated packed type?

        - +

        Overview:
        +

        A packed type is a simple derived type that represents a vector +of elements. Packed types are used when multiple primitive data +are operated in parallel using a single instruction (SIMD). +A packed type requires a size (number of +elements) and an underlying primitive data type. Packed types are +considered first class.

        +
        Syntax:
        +
          < <# elements> x <elementtype> >
        +

        The number of elements is a constant integer value, elementtype may +be any integral or floating point type.

        +
        Examples:
        +

        <4 x int>: Packed vector of 4 integer values.
        +<8 x float>: Packed vector of 8 floating-point values.
        +<2 x uint>: Packed vector of 2 unsigned integer values.

        +

        ---> + @@ -930,7 +937,9 @@

        Binary operators are used to do most of the computation in a program. They require two operands, execute an operation on them, and -produce a single value. The result value of a binary operator is not +produce a single value. Although, that single value might represent +multiple data, as is the case with the packed data type. +The result value of a binary operator is not necessarily the same type as its operands.

        There are several different binary operators:

        @@ -945,8 +954,9 @@

        The 'add' instruction returns the sum of its two operands.

        Arguments:

        The two arguments to the 'add' instruction must be either integer or floating point -values. Both arguments must have identical types.

        + href="#t_integer">integer or floating point values. + This instruction can also take packed versions of the values. +Both arguments must have identical types.

        Semantics:

        The value produced is the integer or floating point sum of the two operands.

        @@ -969,7 +979,9 @@
        Arguments:

        The two arguments to the 'sub' instruction must be either integer or floating point -values. Both arguments must have identical types.

        +values. +This instruction can also take packed versions of the values. +Both arguments must have identical types.

        Semantics:

        The value produced is the integer or floating point difference of the two operands.

        @@ -991,7 +1003,9 @@
        Arguments:

        The two arguments to the 'mul' instruction must be either integer or floating point -values. Both arguments must have identical types.

        +values. +This instruction can also take packed versions of the values. +Both arguments must have identical types.

        Semantics:

        The value produced is the integer or floating point product of the two operands.

        @@ -1014,7 +1028,9 @@
        Arguments:

        The two arguments to the 'div' instruction must be either integer or floating point -values. Both arguments must have identical types.

        +values. +This instruction can also take packed versions of the values. +Both arguments must have identical types.

        Semantics:

        The value produced is the integer or floating point quotient of the two operands.

        @@ -1035,7 +1051,9 @@
        Arguments:

        The two arguments to the 'rem' instruction must be either integer or floating point -values. Both arguments must have identical types.

        +values. +This instruction can also take packed versions of the values. +Both arguments must have identical types.

        Semantics:

        This returns the remainder of a division (where the result has the same sign as the divisor), not the modulus (where the @@ -2593,7 +2611,7 @@ Chris Lattner
        The LLVM Compiler Infrastructure
        - Last modified: $Date: 2004/07/02 21:08:14 $ + Last modified: $Date: 2004/08/12 19:12:28 $ From criswell at cs.uiuc.edu Thu Aug 12 14:50:24 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Thu, 12 Aug 2004 14:50:24 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/test/QMTest/expectations.darwin.qmr Message-ID: <200408121950.OAA26620@choi.cs.uiuc.edu> Changes in directory llvm/test/QMTest: expectations.darwin.qmr updated: 1.5.2.1 -> 1.5.2.2 --- Log message: Made the following two tests XFAIL: Feature.mc.testconstants Feature.mc.testmemory --- Diffs of the changes: (+1 -1) Index: llvm/test/QMTest/expectations.darwin.qmr diff -u llvm/test/QMTest/expectations.darwin.qmr:1.5.2.1 llvm/test/QMTest/expectations.darwin.qmr:1.5.2.2 --- llvm/test/QMTest/expectations.darwin.qmr:1.5.2.1 Fri Aug 6 11:41:09 2004 +++ llvm/test/QMTest/expectations.darwin.qmr Thu Aug 12 14:50:11 2004 @@ -3,13 +3,13 @@ qoq}q(U _Result__kindqUtestqU_Result__outcomeqUPASSqU_Result__annotationsq}U _Result__idq U0Regression.Assembler.2002-08-16-ConstExprInlinedq U_Result__contextq (cqm.test.context Context -q o}q (U_Context__propertiesq}U_Context__temporariesq}ubub.(hoq}q(hhhhh}h U(Regression.Transforms.PruneEH.simpletestqh (h o}q(h}h}ubub.(hoq}q(hhhhh}h U/Regression.CBackend.2002-08-19-HardConstantExprqh (h o}q(h}h}ubub.(hoq}q(hhhhh}h URegression.Jello.test-shiftqh (h o}q(h}h}ubub.(hoq}q(hhhUFAILqh}h U.Regression.Transforms.CorrelatedExprs.looptestqh (h o}q (h}h}ubub.(hoq!}q"(hhhhh}h U-Regression.Linker.2003-08-23-GlobalVarLinkingq#h (h o}q$(h}h}ubub.(hoq%}q&(hhhhh}h U?Regression.Transforms.Inline.2003-09-22-PHINodesInExceptionDestq'h (h o}q((h}h}ubub.(hoq)}q*(hhhhh}h U,Regression.CFrontend.2003-02-12-NonlocalGotoq+h (h o}q,(h}h}ubub.(hoq-}q.(hhhhh}h U2Regression.Transforms.FunctionResolve.retmismatch1q/h (h o}q0(h}h}ubub.(hoq1}q2(hhhhh}h U>Regression.Transforms.LevelRaise.2002-05-02-BadCastEliminationq3h (h o}q4(h}h}ubub.(hoq5}q6(hhhhh}h U8Regression.Transforms.ADCE.2003-01-22-! PredecessorProblemq7h (h o}q8(h}h}ubub.(hoq9}q:(hhhhh}h U=Regression.Transforms.LevelRaise.2002-10-08-VarArgCallInfLoopq;h (h o}q<(h}h}ubub.(hoq=}q>(hhhhh}h U5Regression.CFrontend.2003-07-22-ArrayAccessTypeSafetyq?h (h o}q@(h}h}ubub.(hoqA}qB(hhhhh}h U8Regression.C++Frontend.2003-09-29-ArgumentNumberMismatchqCh (h o}qD(h}h}ubub.(hoqE}qF(hhhhh}h U1Regression.CFrontend.2002-03-12-StructInitializerqGh (h o}qH(h}h}ubub.(hoqI}qJ(hhhhh}h U+Regression.CFrontend.2002-09-19-StarInLabelqKh (h o}qL(h}h}ubub.(hoqM}qN(hhhhh}h U.Regression.CFrontend.2003-08-23-LocalUnionTestqOh (h o}qP(h}h}ubub.(hoqQ}qR(hhhhh}h U-Regression.C++Frontend.2003-08-28-SaveExprBugqSh (h o}qT(h}h}ubub.(hoqU}qV(hhhhh}h U"Regression.Jello.2003-06-05-PHIBugqWh (h o}qX(h}h}ubub.(hoqY}qZ(hhhhh}h U/Regression.Linker.2003-04-26-NullPtrLinkProblemq[h (h o}q\(h}h}ubub.(hoq]}q^(hhhhh}h U)Regression.Transforms.Reassociate.subtestq_h (h o}q`(h}! h}ubub.(hoqa}qb(hhhhh}h U)Regression.Linker.2002-08-20-Constant Exprqch (h o}qd(h}h}ubub.(hoqe}qf(hhhhh}h U=Regression.Transforms.Reassociate.2002-05-15-AgressiveSubMoveqgh (h o}qh(h}h}ubub.(hoqi}qj(hhhhh}h UARegression.Transforms.CorrelatedExprs.2002-10-07-DominatorProblemqkh (h o}ql(h}h}ubub.(hoqm}qn(hhhhh}h U3Regression.Transforms.PiNodeInserter.substitutetestqoh (h o}qp(h}h}ubub.(hoqq}qr(hhhhh}h U4Regression.Transforms.SCCP.2003-08-26-InvokeHandlingqsh (h o}qt(h}h}ubub.(hoqu}qv(hhhhh}h U$Regression.Jello.2003-01-04-LoopTestqwh (h o}qx(h}h}ubub.(hoqy}qz(hhhhh}h U1Regression.Assembler.2002-04-04-PureVirtMethCall2q{h (h o}q|(h}h}ubub.(hoq}}q~(hhhhh}h U)Regression.CFrontend.2002-07-14-MiscTestsqh (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U(hhhhh}h U=Regression.Transforms.LevelRaise.2002-10-08-VarArgCallInfLoopq?h (h o}q@(h}h}ubub.(hoqA}qB(hhhhh}h U5Regression.CFrontend.2003-07-22-ArrayAccessTypeSafetyqCh (h o}qD(h}h}ubub.(hoqE}qF(hhhhh}h U8Regression.C++Frontend.2003-09-29-ArgumentNumberMismatchqGh (h o}qH(h}h}ubub.(hoqI}qJ(hhhhh}h U+Regression.CFrontend.2002-09-19-StarInLabelqKh (h o}qL(h}h}ubub.(hoqM}qN(hhhhh}h U.Regression.CFrontend.2003-08-23-LocalUnionTestqOh (h o}qP(h}h}ubub.(hoqQ}qR(hhhUPASSqSh}h U$Regression.BugPoint.misopt-basictestqTh (h o}qU(h}h}ubub.(hoqV}qW(hhhhh}h U/Regression.Linker.2003-04-26-NullPtrLinkProblemqXh (h o}qY(h}h}ubub.(hoqZ}q[(hhhhh}h U)Regression.Transforms.Reassociate.subtestq\h (h o}q](h}h}ubub.(hoq^}q_(hhhhh}h U)Regression.Linker.2002-08-20-ConstantExprq`h (h o}qa(h}! h}ubub.(hoqb}qc(hhhhh}h U=Regression.Transforms.Reassociate.200 2-05-15-AgressiveSubMoveqdh (h o}qe(h}h}ubub.(hoqf}qg(hhhhh}h UARegression.Transforms.CorrelatedExprs.2002-10-07-DominatorProblemqhh (h o}qi(h}h}ubub.(hoqj}qk(hhhhh}h U3Regression.Transforms.PiNodeInserter.substitutetestqlh (h o}qm(h}h}ubub.(hoqn}qo(hhhhh}h U4Regression.Transforms.SCCP.2003-08-26-InvokeHandlingqph (h o}qq(h}h}ubub.(hoqr}qs(hhhhh}h U-Regression.CFrontend.2002-02-18-64bitConstantqth (h o}qu(h}h}ubub.(hoqv}qw(hhhhh}h U1Regression.Assembler.2002-04-04-PureVirtMethCall2qxh (h o}qy(h}h}ubub.(hoqz}q{(hhhhh}h U(Regression.Reoptimizer.BinInterface.testq|h (h o}q}(h}h}ubub.(hoq~}q(hhhhh}h URegression.Transforms.CorrelatedExprs! .2002-10-08-DominatorTestq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h URegression.Linker.testlink2q?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U(Regression.Transforms.GCSE.RLE-Eliminateq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U4Regression.C++Frontend.2003-09-30-NestedFunctionDeclq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U=Regression.Transforms.CorrelatedExprs.2002-09-23-PHIUpdateBugq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U7Regression.Transforms.LowerSwitch.2003-05-01-PHIProblemq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U2Regression.Transforms.ADCE.2003-09-15-InfLoopCrashq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U*Regression.Transforms.DSAnalysis.recursionq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U)Regression.Jello.2003-01-15-AlignmentTestq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhUPASSq?h}h UFeature.mc.simplecalltestq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U*Regression.CFrontend.2002-04-07-SwitchStmtq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh! }h U!Regression.Jello.2003-01-10-FUCOMq?h (h o}q?(h}h}ubub.(hoq?}q ?(hhhhh}h U(Regression.CFrontend.2003-08-21-StmtExprq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhUPASSq?h}h U*Regression.Transforms.ScalarRepl.basictestq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhh"h}h U6Regression.Transforms.LevelRaise.2002-02-11-ArrayShapeq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U1Regression.Assembler.2003-03-03-DuplicateConstantq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U.Regression.Transforms.ModuloSched.arith-simpleq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U%Regression.Transforms.InstCombine.andq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U)Regression.Other.2002-08-02-DomSetProblemq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U6Regression.Assembler.2002-07-25-ParserAssertionFailureq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U6Regression.Transforms.LevelRaise.2002-03-20-BadCodegenq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U%Regression.Transforms.ADCE.basictest1q?h (h o}q?(h}h}ubub.(hoq?}q?(hhhUPASSq?h}h UFeature.mc.recursivetypeq?! h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U$Regression.Transforms.InstCombine.orq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U Regression.Verifier.AmbiguousPhiq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U'Regression.Analysis.DSGraph.constantizeq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U6Regression.Transforms.GlobalDCE.2002-08-17-FunctionDGEq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U4Regression.Transforms.SimplifyCFG.2002-06-24-PHINodeq?h (h o}q?(h}h}ubub.(hoq?}q?(hhhhh}h U(Regression.Linker.2003-05-15-TypeProblemq?h (h o}r+++++++++ \ No newline at end of file From brukman at cs.uiuc.edu Thu Aug 12 14:58:53 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Thu, 12 Aug 2004 14:58:53 -0500 Subject: [llvm-commits] CVS: llvm/docs/ExtendingLLVM.html Message-ID: <200408121958.OAA01972@zion.cs.uiuc.edu> Changes in directory llvm/docs: ExtendingLLVM.html updated: 1.10 -> 1.11 --- Log message: * Escape &, <, and > * Wrap code in or for larger blocks,

        * Wrap lines at 80 cols --- Diffs of the changes: (+25 -16) Index: llvm/docs/ExtendingLLVM.html diff -u llvm/docs/ExtendingLLVM.html:1.10 llvm/docs/ExtendingLLVM.html:1.11 --- llvm/docs/ExtendingLLVM.html:1.10 Thu Aug 12 14:06:24 2004 +++ llvm/docs/ExtendingLLVM.html Thu Aug 12 14:58:43 2004 @@ -220,7 +220,8 @@ add enum for the type
      • llvm/include/llvm/Type.h: - add ID number for the new type; add a forward declaration of the type also
      • + add ID number for the new type; add a forward declaration of the type + also
      • llvm/include/llvm/DerivedType.h: add new class to represent new class in the hierarchy; add forward @@ -228,29 +229,37 @@
      • llvm/lib/VMCore/Type.cpp: add support for derived type to: - std::string getTypeDescription(const Type &Ty, - std::vector &TypeStack) - bool TypesEqual(const Type* Ty, const Type *Ty2, - std::map & EqTypes) - add necessary member functions for type, and factory - methods
      • +
        +
        +std::string getTypeDescription(const Type &Ty,
        +  std::vector<const Type*> &TypeStack)
        +bool TypesEqual(const Type *Ty, const Type *Ty2,
        +  std::map<const Type*, const Type*> & EqTypes)
        +
        +
        + add necessary member functions for type, and factory methods
      • llvm/lib/AsmReader/Lexer.l: add ability to parse in the type from text assembly
      • llvm/lib/ByteCode/Writer/Writer.cpp: - modify void BytecodeWriter::outputType(const Type *T) to - serialize your type
      • + modify void BytecodeWriter::outputType(const Type *T) to serialize + your type
      • llvm/lib/ByteCode/Reader/Reader.cpp: - modify const Type *BytecodeReader::ParseType() to - read your data type
      • + modify const Type *BytecodeReader::ParseType() to read your data + type
      • llvm/lib/VMCore/AsmWriter.cpp: - modify void calcTypeName(const Type *Ty, - std::vector &TypeStack, - std::map &TypeNames, - std::string & Result) + modify +
        +
        +void calcTypeName(const Type *Ty,
        +                  std::vector<const Type*> &TypeStack,
        +                  std::map<const Type*,std::string> &TypeNames,
        +                  std::string & Result)
        +
        +
        to output the new derived type
      • @@ -271,7 +280,7 @@ Misha Brukman
        The LLVM Compiler Infrastructure
        - Last modified: $Date: 2004/08/12 19:06:24 $ + Last modified: $Date: 2004/08/12 19:58:43 $ From brukman at cs.uiuc.edu Thu Aug 12 15:16:18 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Thu, 12 Aug 2004 15:16:18 -0500 Subject: [llvm-commits] CVS: llvm/docs/LangRef.html Message-ID: <200408122016.PAA02197@zion.cs.uiuc.edu> Changes in directory llvm/docs: LangRef.html updated: 1.72 -> 1.73 --- Log message: Wrap long lines and try to fill the 80 chars per line so that we don't have too many short lines. --- Diffs of the changes: (+26 -22) Index: llvm/docs/LangRef.html diff -u llvm/docs/LangRef.html:1.72 llvm/docs/LangRef.html:1.73 --- llvm/docs/LangRef.html:1.72 Thu Aug 12 14:12:28 2004 +++ llvm/docs/LangRef.html Thu Aug 12 15:16:08 2004 @@ -389,7 +389,8 @@ integral - bool, ubyte, sbyte, ushort, short, uint, int, ulong, long + bool, ubyte, sbyte, ushort, short, uint, int, ulong, long + floating point @@ -397,8 +398,9 @@ first class - bool, ubyte, sbyte, ushort, short,
        -uint, int, ulong, long, float, double, pointer, packed
        + bool, ubyte, sbyte, ushort, short, uint, int, ulong, long,
        + float, double, pointer, + packed
        @@ -467,8 +469,8 @@

        Syntax:
          <returntype> (<parameter list>)
        -

        Where '<parameter list>' is a comma-separated list of -type specifiers. Optionally, the parameter list may include a type ..., +

        Where '<parameter list>' is a comma-separated list of type +specifiers. Optionally, the parameter list may include a type ..., which indicates that the function takes a variable number of arguments. Variable argument functions can access their arguments with the variable argument handling intrinsic functions.

        @@ -482,16 +484,16 @@ float (int, int *) * - : Pointer to a function that takes -an int and a pointer to int, -returning float. + : Pointer to a function that takes an + int and a pointer to int, + returning float. int (sbyte *, ...) : A vararg function that takes at least one pointer to sbyte (signed char in C), -which returns an integer. This is the signature for printf -in LLVM. + href="#t_pointer">pointer to sbyte (signed char in C), which + returns an integer. This is the signature for printf in + LLVM. @@ -521,10 +523,10 @@ { float, int (int) * } - : A pair, where the first element is a float and the -second element is a pointer to a function that takes an int, returning -an int. + : A pair, where the first element is a float and the second + element is a pointer to a function that takes an int, returning an + int. @@ -544,14 +546,14 @@ [4x int]* - : pointer to array -of four int values + : pointer to array of + four int values int (int *) * : A pointer to a function that takes an int, returning -an int. + href="#t_function">function that takes an int, returning an + int. @@ -579,8 +581,10 @@ - - + + +

        LLVM programs are composed of "Module"s, each of which is a translation unit of the input programs. Each module consists of @@ -2611,7 +2615,7 @@ Chris Lattner
        The LLVM Compiler Infrastructure
        - Last modified: $Date: 2004/08/12 19:12:28 $ + Last modified: $Date: 2004/08/12 20:16:08 $ From criswell at cs.uiuc.edu Thu Aug 12 17:18:54 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Thu, 12 Aug 2004 17:18:54 -0500 Subject: [llvm-commits] CVS: llvm-www/RandomBoxes/012-Modular.html Message-ID: <200408122218.RAA05415@choi.cs.uiuc.edu> Changes in directory llvm-www/RandomBoxes: 012-Modular.html updated: 1.1 -> 1.2 --- Log message: Fixed grammar typo. --- Diffs of the changes: (+1 -1) Index: llvm-www/RandomBoxes/012-Modular.html diff -u llvm-www/RandomBoxes/012-Modular.html:1.1 llvm-www/RandomBoxes/012-Modular.html:1.2 --- llvm-www/RandomBoxes/012-Modular.html:1.1 Fri May 28 14:24:58 2004 +++ llvm-www/RandomBoxes/012-Modular.html Thu Aug 12 17:18:42 2004 @@ -1,3 +1,3 @@ -LLVM is a completely modular compiler infrastructure that allows you +LLVM is a completely modular compiler infrastructure that allows you to build compiler related tools with ease. Simply pick the front-end, optimizations, code generator, or other components that you need for your tool. From lattner at cs.uiuc.edu Thu Aug 12 20:31:31 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 20:31:31 -0500 Subject: [llvm-commits] CVS: llvm/test/Programs/External/SPEC/CINT95/132.ijpeg/Makefile Message-ID: <200408130131.UAA24284@apoc.cs.uiuc.edu> Changes in directory llvm/test/Programs/External/SPEC/CINT95/132.ijpeg: Makefile updated: 1.4 -> 1.5 --- Log message: #include errno.h --- Diffs of the changes: (+3 -0) Index: llvm/test/Programs/External/SPEC/CINT95/132.ijpeg/Makefile diff -u llvm/test/Programs/External/SPEC/CINT95/132.ijpeg/Makefile:1.4 llvm/test/Programs/External/SPEC/CINT95/132.ijpeg/Makefile:1.5 --- llvm/test/Programs/External/SPEC/CINT95/132.ijpeg/Makefile:1.4 Fri Mar 5 21:53:04 2004 +++ llvm/test/Programs/External/SPEC/CINT95/132.ijpeg/Makefile Thu Aug 12 20:31:18 2004 @@ -12,5 +12,8 @@ # extern char * sys_errlist variable from linking properly. CPPFLAGS += -D__const="" +# This #define is the perfectly logical way to get 132.ijpeg to #include errno.h +CPPFLAGS += -D__VMS + Source=libpbm1.c libpbm2.c libpbm3.c libpbm4.c libpbm5.c libpgm1.c libpgm2.c libppm1.c libppm2.c libppm3.c libppm4.c libppm5.c spec_image.c spec_jmemdst.c spec_jmemsrc.c spec_main.c rdppm.c wrppm.c rdgif.c wrgif.c rdtarga.c wrtarga.c rdbmp.c wrbmp.c jcapi.c jcparam.c jdatadst.c jcmaster.c jcmarker.c jcmainct.c jcprepct.c jccoefct.c jccolor.c jcsample.c jchuff.c jcdctmgr.c jfdctfst.c jfdctflt.c jfdctint.c jdapi.c jdatasrc.c jdmaster.c jdmarker.c jdmainct.c jdcoefct.c jdpostct.c jddctmgr.c jidctfst.c jidctflt.c jidctint.c jidctred.c jdhuff.c jdsample.c jdcolor.c jquant1.c jquant2.c jdmerge.c jcomapi.c jutils.c jerror.c jmemmgr.c jmemnobs.c include ../../Makefile.spec95 From brukman at cs.uiuc.edu Thu Aug 12 20:47:00 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Thu, 12 Aug 2004 20:47:00 -0500 Subject: [llvm-commits] CVS: llvm/test/Programs/External/Makefile Message-ID: <200408130147.UAA29784@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/External: Makefile updated: 1.7 -> 1.8 --- Log message: Test SPEC and Povray in parallel, so that if either fails, the other goes on --- Diffs of the changes: (+2 -2) Index: llvm/test/Programs/External/Makefile diff -u llvm/test/Programs/External/Makefile:1.7 llvm/test/Programs/External/Makefile:1.8 --- llvm/test/Programs/External/Makefile:1.7 Thu Feb 26 23:59:09 2004 +++ llvm/test/Programs/External/Makefile Thu Aug 12 20:46:49 2004 @@ -8,10 +8,10 @@ # # Create the list of directories to compile # -DIRS := SPEC Povray +PARALLEL_DIRS := SPEC Povray ifndef USE_POVRAY -DIRS := $(filter-out Povray/, $(DIRS)) +PARALLEL_DIRS := $(filter-out Povray/, $(DIRS)) endif include ${LEVEL}/test/Programs/Makefile.programs From brukman at cs.uiuc.edu Thu Aug 12 20:55:51 2004 From: brukman at cs.uiuc.edu (Misha Brukman) Date: Thu, 12 Aug 2004 20:55:51 -0500 Subject: [llvm-commits] CVS: llvm/test/Programs/External/Makefile Message-ID: <200408130155.UAA30544@zion.cs.uiuc.edu> Changes in directory llvm/test/Programs/External: Makefile updated: 1.8 -> 1.9 --- Log message: Fix bug in previous checkin. --- Diffs of the changes: (+1 -1) Index: llvm/test/Programs/External/Makefile diff -u llvm/test/Programs/External/Makefile:1.8 llvm/test/Programs/External/Makefile:1.9 --- llvm/test/Programs/External/Makefile:1.8 Thu Aug 12 20:46:49 2004 +++ llvm/test/Programs/External/Makefile Thu Aug 12 20:55:41 2004 @@ -11,7 +11,7 @@ PARALLEL_DIRS := SPEC Povray ifndef USE_POVRAY -PARALLEL_DIRS := $(filter-out Povray/, $(DIRS)) +PARALLEL_DIRS := $(filter-out Povray/, $(PARALLEL_DIRS)) endif include ${LEVEL}/test/Programs/Makefile.programs From natebegeman at mac.com Thu Aug 12 21:19:36 2004 From: natebegeman at mac.com (Nate Begeman) Date: Thu, 12 Aug 2004 21:19:36 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td PowerPCInstrInfo.td Message-ID: <200408130219.VAA31602@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PowerPCInstrFormats.td updated: 1.11 -> 1.12 PowerPCInstrInfo.td updated: 1.19 -> 1.20 --- Log message: Add some more 64 bit instructions we need for the PowerPC-64 ISel to the tablegen files --- Diffs of the changes: (+57 -2) Index: llvm/lib/Target/PowerPC/PowerPCInstrFormats.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.11 llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.12 --- llvm/lib/Target/PowerPC/PowerPCInstrFormats.td:1.11 Wed Aug 11 15:56:14 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrFormats.td Thu Aug 12 21:19:25 2004 @@ -37,6 +37,7 @@ def Sgr : Format<20>; def Imm15 : Format<21>; def Vpr : Format<22>; +def Imm6 : Format<23>; //===----------------------------------------------------------------------===// // @@ -266,6 +267,7 @@ let Inst{31} = rc; } + class XForm_1 opcode, bits<10> xo, bit ppc64, bit vmx> : XForm_base_r3xo; @@ -448,6 +450,28 @@ let SPR = spr; } +// 1.7.10 XS-Form +class XSForm_1 opcode, bits<9> xo, bit rc, + bit ppc64, bit vmx> : I { + field bits<5> RS; + field bits<5> A; + field bits<6> SH; + + let ArgCount = 3; + let Arg0Type = Gpr.Value; + let Arg1Type = Gpr.Value; + let Arg2Type = Imm6.Value; + let Arg3Type = 0; + let Arg4Type = 0; + + let Inst{6-10} = RS; + let Inst{11-15} = A; + let Inst{16-20} = SH{1-5}; + let Inst{21-29} = xo; + let Inst{30} = SH{0}; + let Inst{31} = rc; +} + // 1.7.11 XO-Form class XOForm_1 opcode, bits<9> xo, bit oe, bit rc, bit ppc64, bit vmx> : I { @@ -563,6 +587,30 @@ let Arg2Type = Imm5.Value; } +// 1.7.14 MD-Form +class MDForm_1 opcode, bits<3> xo, bit rc, bit ppc64, bit vmx> + : I { + let ArgCount = 4; + field bits<5> RS; + field bits<5> RA; + field bits<6> SH; + field bits<6> MBE; + + let Arg0Type = Gpr.Value; + let Arg1Type = Gpr.Value; + let Arg2Type = Imm6.Value; + let Arg3Type = Imm6.Value; + let Arg4Type = 0; + + let Inst{6-10} = RS; + let Inst{11-15} = RA; + let Inst{16-20} = SH{1-5}; + let Inst{21-26} = MBE; + let Inst{27-29} = xo; + let Inst{30} = SH{0}; + let Inst{31} = rc; +} + //===----------------------------------------------------------------------===// class Pseudo : I { Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.td diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.19 llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.20 --- llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.19 Wed Aug 11 18:33:34 2004 +++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.td Thu Aug 12 21:19:26 2004 @@ -123,6 +123,7 @@ def MFCTR : XFXForm_1_ext<"mfctr", 31, 399, 9, 0, 0>; def MTLR : XFXForm_7_ext<"mtlr", 31, 467, 8, 0, 0>; def MTCTR : XFXForm_7_ext<"mtctr", 31, 467, 9, 0, 0>; +def MULLD : XOForm_1<"mulld", 31, 233, 0, 0, 1, 0>; def MULLW : XOForm_1<"mullw", 31, 235, 0, 0, 0, 0>; def MULHWU : XOForm_2<"mulhwu", 31, 11, 0, 0, 0>; def NAND : XForm_6<"nand", 31, 476, 0, 0, 0>; @@ -133,13 +134,19 @@ def ORIS : DForm_4<"oris", 25, 0, 0>; def OR : XForm_6<"or", 31, 444, 0, 0, 0>; def ORo : XForm_6<"or.", 31, 444, 1, 0, 0>; +def RLDICL : MDForm_1<"rldicl", 30, 0, 0, 1, 0>; +def RLDICR : MDForm_1<"rldicr", 30, 1, 0, 1, 0>; def RLWINM : MForm_2<"rlwinm", 21, 0, 0, 0>; def RLWNM : MForm_1<"rlwnm", 23, 0, 0, 0>; def RLWIMI : MForm_2<"rlwimi", 20, 0, 0, 0>; +def SLD : XForm_6<"sld", 31, 27, 0, 1, 0>; def SLW : XForm_6<"slw", 31, 24, 0, 0, 0>; -def SRW : XForm_6<"srw", 31, 24, 0, 0, 0>; +def SRD : XForm_6<"srd", 31, 539, 0, 1, 0>; +def SRW : XForm_6<"srw", 31, 536, 0, 0, 0>; +def SRADI : XSForm_1<"sradi", 31, 413, 0, 1, 0>; def SRAWI : XForm_10<"srawi", 31, 824, 0, 0, 0>; -def SRAW : XForm_6<"sraw", 31, 280, 0, 0, 0>; +def SRAD : XForm_6<"srad", 31, 794, 0, 1, 0>; +def SRAW : XForm_6<"sraw", 31, 792, 0, 0, 0>; def STB : DForm_3<"stb", 38, 0, 0>; def STBU : DForm_3<"stbu", 39, 0, 0>; def STBX : XForm_8<"stbx", 31, 215, 0, 0>; From natebegeman at mac.com Thu Aug 12 21:20:57 2004 From: natebegeman at mac.com (Nate Begeman) Date: Thu, 12 Aug 2004 21:20:57 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp Message-ID: <200408130220.VAA31624@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC64ISelSimple.cpp updated: 1.3 -> 1.4 --- Log message: Longs are in one register on PowerPC 64; use appropriate instructions to operate on them. --- Diffs of the changes: (+22 -158) Index: llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp diff -u llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp:1.3 llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp:1.4 --- llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp:1.3 Wed Aug 11 22:30:03 2004 +++ llvm/lib/Target/PowerPC/PPC64ISelSimple.cpp Thu Aug 12 21:20:47 2004 @@ -1867,38 +1867,14 @@ // 64 x 64 -> 64 if (Class0 == cLong && Class1 == cLong) { - unsigned Tmp1 = makeAnotherReg(Type::IntTy); - unsigned Tmp2 = makeAnotherReg(Type::IntTy); - unsigned Tmp3 = makeAnotherReg(Type::IntTy); - unsigned Tmp4 = makeAnotherReg(Type::IntTy); - // FIXME: long is not split into two regs - BuildMI(*MBB, IP, PPC::MULHWU, 2, Tmp1).addReg(Op0r+1).addReg(Op1r+1); - BuildMI(*MBB, IP, PPC::MULLW, 2, DestReg+1).addReg(Op0r+1).addReg(Op1r+1); - BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp2).addReg(Op0r+1).addReg(Op1r); - BuildMI(*MBB, IP, PPC::ADD, 2, Tmp3).addReg(Tmp1).addReg(Tmp2); - BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp4).addReg(Op0r).addReg(Op1r+1); - BuildMI(*MBB, IP, PPC::ADD, 2, DestReg).addReg(Tmp3).addReg(Tmp4); + BuildMI(*MBB, IP, PPC::MULLD, 2, DestReg).addReg(Op0r).addReg(Op1r); return; } // 64 x 32 or less, promote 32 to 64 and do a 64 x 64 if (Class0 == cLong && Class1 <= cInt) { - unsigned Tmp0 = makeAnotherReg(Type::IntTy); - unsigned Tmp1 = makeAnotherReg(Type::IntTy); - unsigned Tmp2 = makeAnotherReg(Type::IntTy); - unsigned Tmp3 = makeAnotherReg(Type::IntTy); - unsigned Tmp4 = makeAnotherReg(Type::IntTy); - if (Op1->getType()->isSigned()) - BuildMI(*MBB, IP, PPC::SRAWI, 2, Tmp0).addReg(Op1r).addImm(31); - else - BuildMI(*MBB, IP, PPC::LI, 2, Tmp0).addSImm(0); - // FIXME: long is not split into two regs - BuildMI(*MBB, IP, PPC::MULHWU, 2, Tmp1).addReg(Op0r+1).addReg(Op1r); - BuildMI(*MBB, IP, PPC::MULLW, 2, DestReg+1).addReg(Op0r+1).addReg(Op1r); - BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp2).addReg(Op0r+1).addReg(Tmp0); - BuildMI(*MBB, IP, PPC::ADD, 2, Tmp3).addReg(Tmp1).addReg(Tmp2); - BuildMI(*MBB, IP, PPC::MULLW, 2, Tmp4).addReg(Op0r).addReg(Op1r); - BuildMI(*MBB, IP, PPC::ADD, 2, DestReg).addReg(Tmp3).addReg(Tmp4); + // FIXME: CLEAR or SIGN EXTEND Op1 + BuildMI(*MBB, IP, PPC::MULLD, 2, DestReg).addReg(Op0r).addReg(Op1r); return; } @@ -2139,103 +2115,27 @@ // if (ConstantUInt *CUI = dyn_cast(ShiftAmount)) { unsigned Amount = CUI->getValue(); - if (Amount < 32) { - if (isLeftShift) { - // FIXME: RLWIMI is a use-and-def of DestReg+1, but that violates SSA - // FIXME: long - BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) - .addImm(Amount).addImm(0).addImm(31-Amount); - BuildMI(*MBB, IP, PPC::RLWIMI, 5).addReg(DestReg).addReg(SrcReg+1) - .addImm(Amount).addImm(32-Amount).addImm(31); - BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg+1).addReg(SrcReg+1) - .addImm(Amount).addImm(0).addImm(31-Amount); - } else { - // FIXME: RLWIMI is a use-and-def of DestReg, but that violates SSA - // FIXME: long - BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg+1).addReg(SrcReg+1) - .addImm(32-Amount).addImm(Amount).addImm(31); - BuildMI(*MBB, IP, PPC::RLWIMI, 5).addReg(DestReg+1).addReg(SrcReg) - .addImm(32-Amount).addImm(0).addImm(Amount-1); - BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg) - .addImm(32-Amount).addImm(Amount).addImm(31); - } - } else { // Shifting more than 32 bits - Amount -= 32; - if (isLeftShift) { - if (Amount != 0) { - // FIXME: long - BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg).addReg(SrcReg+1) - .addImm(Amount).addImm(0).addImm(31-Amount); - } else { - // FIXME: long - BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg+1) - .addReg(SrcReg+1); - } - BuildMI(*MBB, IP, PPC::LI, 1, DestReg+1).addSImm(0); + assert(Amount < 64 && "Invalid immediate shift amount!"); + if (isLeftShift) { + BuildMI(*MBB, IP, PPC::RLDICR, 3, DestReg).addReg(SrcReg).addImm(Amount) + .addImm(63-Amount); + } else { + if (isSigned) { + BuildMI(*MBB, IP, PPC::SRADI, 2, DestReg).addReg(SrcReg) + .addImm(Amount); } else { - if (Amount != 0) { - if (isSigned) - BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg+1).addReg(SrcReg) - .addImm(Amount); - else - BuildMI(*MBB, IP, PPC::RLWINM, 4, DestReg+1).addReg(SrcReg) - .addImm(32-Amount).addImm(Amount).addImm(31); - } else { - BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) - .addReg(SrcReg); - } - BuildMI(*MBB, IP,PPC::LI, 1, DestReg).addSImm(0); + BuildMI(*MBB, IP, PPC::RLDICL, 3, DestReg).addReg(SrcReg) + .addImm(64-Amount).addImm(Amount); } } } else { - unsigned TmpReg1 = makeAnotherReg(Type::IntTy); - unsigned TmpReg2 = makeAnotherReg(Type::IntTy); - unsigned TmpReg3 = makeAnotherReg(Type::IntTy); - unsigned TmpReg4 = makeAnotherReg(Type::IntTy); - unsigned TmpReg5 = makeAnotherReg(Type::IntTy); - unsigned TmpReg6 = makeAnotherReg(Type::IntTy); - unsigned ShiftAmountReg = getReg (ShiftAmount, MBB, IP); - + unsigned ShiftReg = getReg (ShiftAmount, MBB, IP); + if (isLeftShift) { - BuildMI(*MBB, IP, PPC::SUBFIC, 2, TmpReg1).addReg(ShiftAmountReg) - .addSImm(32); - BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg2).addReg(SrcReg) - .addReg(ShiftAmountReg); - BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg3).addReg(SrcReg+1) - .addReg(TmpReg1); - BuildMI(*MBB, IP, PPC::OR, 2,TmpReg4).addReg(TmpReg2).addReg(TmpReg3); - BuildMI(*MBB, IP, PPC::ADDI, 2, TmpReg5).addReg(ShiftAmountReg) - .addSImm(-32); - BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg6).addReg(SrcReg+1) - .addReg(TmpReg5); - BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(TmpReg4) - .addReg(TmpReg6); - BuildMI(*MBB, IP, PPC::SLW, 2, DestReg+1).addReg(SrcReg+1) - .addReg(ShiftAmountReg); + BuildMI(*MBB, IP, PPC::SLD, 2, DestReg).addReg(SrcReg).addReg(ShiftReg); } else { - if (isSigned) { - // FIXME: Unimplemented - // Page C-3 of the PowerPC 32bit Programming Environments Manual - std::cerr << "ERROR: Unimplemented: signed right shift of long\n"; - abort(); - } else { - BuildMI(*MBB, IP, PPC::SUBFIC, 2, TmpReg1).addReg(ShiftAmountReg) - .addSImm(32); - BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg2).addReg(SrcReg+1) - .addReg(ShiftAmountReg); - BuildMI(*MBB, IP, PPC::SLW, 2, TmpReg3).addReg(SrcReg) - .addReg(TmpReg1); - BuildMI(*MBB, IP, PPC::OR, 2, TmpReg4).addReg(TmpReg2) - .addReg(TmpReg3); - BuildMI(*MBB, IP, PPC::ADDI, 2, TmpReg5).addReg(ShiftAmountReg) - .addSImm(-32); - BuildMI(*MBB, IP, PPC::SRW, 2, TmpReg6).addReg(SrcReg) - .addReg(TmpReg5); - BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(TmpReg4) - .addReg(TmpReg6); - BuildMI(*MBB, IP, PPC::SRW, 2, DestReg).addReg(SrcReg) - .addReg(ShiftAmountReg); - } + unsigned Opcode = (isSigned) ? PPC::SRAD : PPC::SRD; + BuildMI(*MBB, IP, Opcode, DestReg).addReg(SrcReg).addReg(ShiftReg); } } return; @@ -2688,16 +2588,7 @@ if (sourceUnsigned && destUnsigned) { // handle long dest class now to keep switch clean if (DestClass == cLong) { - // FIXME: long - if (SrcClass == cLong) { - BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); - BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg+1) - .addReg(SrcReg+1); - } else { - BuildMI(*MBB, IP, PPC::LI, 1, DestReg).addSImm(0); - BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) - .addReg(SrcReg); - } + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); return; } @@ -2730,16 +2621,7 @@ if (!sourceUnsigned && !destUnsigned) { // handle long dest class now to keep switch clean if (DestClass == cLong) { - // FIXME: long - if (SrcClass == cLong) { - BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); - BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg+1) - .addReg(SrcReg+1); - } else { - BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg).addReg(SrcReg).addImm(31); - BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) - .addReg(SrcReg); - } + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); return; } @@ -2778,16 +2660,7 @@ if (sourceUnsigned && !destUnsigned) { // handle long dest class now to keep switch clean if (DestClass == cLong) { - // FIXME: long - if (SrcClass == cLong) { - BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); - BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg+1). - addReg(SrcReg+1); - } else { - BuildMI(*MBB, IP, PPC::LI, 1, DestReg).addSImm(0); - BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) - .addReg(SrcReg); - } + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); return; } @@ -2830,16 +2703,7 @@ if (!sourceUnsigned && destUnsigned) { // handle long dest class now to keep switch clean if (DestClass == cLong) { - // FIXME: long - if (SrcClass == cLong) { - BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); - BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg+1) - .addReg(SrcReg+1); - } else { - BuildMI(*MBB, IP, PPC::SRAWI, 2, DestReg).addReg(SrcReg).addImm(31); - BuildMI(*MBB, IP, PPC::OR, 2, DestReg+1).addReg(SrcReg) - .addReg(SrcReg); - } + BuildMI(*MBB, IP, PPC::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg); return; } From lattner at cs.uiuc.edu Thu Aug 12 21:43:31 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 21:43:31 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/ValueMapper.cpp Message-ID: <200408130243.VAA26527@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: ValueMapper.cpp updated: 1.17 -> 1.18 --- Log message: Add value mapper support for select constant exprs. This should fix a bug Nate ran into when bugpointing siod. This fix should go into LLVM 1.3 --- Diffs of the changes: (+5 -0) Index: llvm/lib/Transforms/Utils/ValueMapper.cpp diff -u llvm/lib/Transforms/Utils/ValueMapper.cpp:1.17 llvm/lib/Transforms/Utils/ValueMapper.cpp:1.18 --- llvm/lib/Transforms/Utils/ValueMapper.cpp:1.17 Wed Aug 4 03:22:15 2004 +++ llvm/lib/Transforms/Utils/ValueMapper.cpp Thu Aug 12 21:43:19 2004 @@ -81,6 +81,11 @@ for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i) Idx.push_back(cast(MapValue(CE->getOperand(i), VM))); return VMSlot = ConstantExpr::getGetElementPtr(MV, Idx); + } else if (CE->getOpcode() == Instruction::Select) { + Constant *MV1 = cast(MapValue(CE->getOperand(0), VM)); + Constant *MV2 = cast(MapValue(CE->getOperand(1), VM)); + Constant *MV3 = cast(MapValue(CE->getOperand(2), VM)); + return VMSlot = ConstantExpr::getSelect(MV1, MV2, MV3); } else { assert(CE->getNumOperands() == 2 && "Must be binary operator?"); Constant *MV1 = cast(MapValue(CE->getOperand(0), VM)); From lattner at cs.uiuc.edu Thu Aug 12 22:03:56 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 22:03:56 -0500 Subject: [llvm-commits] CVS: llvm/include/llvm/Transforms/IPO.h Message-ID: <200408130303.WAA29295@apoc.cs.uiuc.edu> Changes in directory llvm/include/llvm/Transforms: IPO.h updated: 1.33 -> 1.34 --- Log message: Add a pass --- Diffs of the changes: (+8 -0) Index: llvm/include/llvm/Transforms/IPO.h diff -u llvm/include/llvm/Transforms/IPO.h:1.33 llvm/include/llvm/Transforms/IPO.h:1.34 --- llvm/include/llvm/Transforms/IPO.h:1.33 Sun Jun 27 19:43:25 2004 +++ llvm/include/llvm/Transforms/IPO.h Thu Aug 12 22:03:44 2004 @@ -15,10 +15,13 @@ #ifndef LLVM_TRANSFORMS_IPO_H #define LLVM_TRANSFORMS_IPO_H +#include + namespace llvm { class Pass; class Function; +class BasicBlock; //===----------------------------------------------------------------------===// /// createLowerSetJmpPass - This function lowers the setjmp/longjmp intrinsics @@ -136,6 +139,11 @@ /// Pass *createSingleLoopExtractorPass(); +// createBlockExtractorPass - This pass extracts all blocks (except those +// specified in the argument list) from the functions in the module. +// +Pass *llvm::createBlockExtractorPass(std::vector &BTNE); + } // End llvm namespace #endif From lattner at cs.uiuc.edu Thu Aug 12 22:05:28 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 22:05:28 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/IPO/LoopExtractor.cpp Message-ID: <200408130305.WAA30233@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/IPO: LoopExtractor.cpp updated: 1.12 -> 1.13 --- Log message: "extract" the block extractor pass from bugpoint (haha) --- Diffs of the changes: (+53 -0) Index: llvm/lib/Transforms/IPO/LoopExtractor.cpp diff -u llvm/lib/Transforms/IPO/LoopExtractor.cpp:1.12 llvm/lib/Transforms/IPO/LoopExtractor.cpp:1.13 --- llvm/lib/Transforms/IPO/LoopExtractor.cpp:1.12 Thu Jul 29 12:28:42 2004 +++ llvm/lib/Transforms/IPO/LoopExtractor.cpp Thu Aug 12 22:05:17 2004 @@ -129,3 +129,56 @@ Pass *llvm::createSingleLoopExtractorPass() { return new SingleLoopExtractor(); } + + +namespace { + /// BlockExtractorPass - This pass is used by bugpoint to extract all blocks + /// from the module into their own functions except for those specified by the + /// BlocksToNotExtract list. + class BlockExtractorPass : public Pass { + std::vector BlocksToNotExtract; + public: + BlockExtractorPass(std::vector &B) : BlocksToNotExtract(B) {} + BlockExtractorPass() {} + + bool run(Module &M); + }; + RegisterOpt + XX("extract-blocks", "Extract Basic Blocks From Module (for bugpoint use)"); +} + +// createBlockExtractorPass - This pass extracts all blocks (except those +// specified in the argument list) from the functions in the module. +// +Pass *llvm::createBlockExtractorPass(std::vector &BTNE) { + return new BlockExtractorPass(BTNE); +} + +bool BlockExtractorPass::run(Module &M) { + std::set TranslatedBlocksToNotExtract; + for (unsigned i = 0, e = BlocksToNotExtract.size(); i != e; ++i) { + BasicBlock *BB = BlocksToNotExtract[i]; + Function *F = BB->getParent(); + + // Map the corresponding function in this module. + Function *MF = M.getFunction(F->getName(), F->getFunctionType()); + + // Figure out which index the basic block is in its function. + Function::iterator BBI = MF->begin(); + std::advance(BBI, std::distance(F->begin(), Function::iterator(BB))); + TranslatedBlocksToNotExtract.insert(BBI); + } + + // Now that we know which blocks to not extract, figure out which ones we WANT + // to extract. + std::vector BlocksToExtract; + for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) + for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) + if (!TranslatedBlocksToNotExtract.count(BB)) + BlocksToExtract.push_back(BB); + + for (unsigned i = 0, e = BlocksToExtract.size(); i != e; ++i) + ExtractBasicBlock(BlocksToExtract[i]); + + return !BlocksToExtract.empty(); +} From lattner at cs.uiuc.edu Thu Aug 12 22:09:07 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 22:09:07 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/CodeExtractor/BlockExtractPHI.ll Message-ID: <200408130309.WAA30388@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/CodeExtractor: BlockExtractPHI.ll added (r1.1) --- Log message: New testcase, which causes the block extractor to barf --- Diffs of the changes: (+12 -0) Index: llvm/test/Regression/Transforms/CodeExtractor/BlockExtractPHI.ll diff -c /dev/null llvm/test/Regression/Transforms/CodeExtractor/BlockExtractPHI.ll:1.1 *** /dev/null Thu Aug 12 22:09:04 2004 --- llvm/test/Regression/Transforms/CodeExtractor/BlockExtractPHI.ll Thu Aug 12 22:08:54 2004 *************** *** 0 **** --- 1,12 ---- + ; RUN: llvm-as < %s | opt -extract-blocks -disable-output + + implementation + + void %l102_yyparse() { + no_exit.0.i: + br bool false, label %yylex.entry, label %yylex.entry + + yylex.entry: + %tmp.1027 = phi int [ 0, %no_exit.0.i ], [ 0, %no_exit.0.i ] + ret void + } From lattner at cs.uiuc.edu Thu Aug 12 22:17:52 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 22:17:52 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/CodeExtractor.cpp Message-ID: <200408130317.WAA30814@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: CodeExtractor.cpp updated: 1.28 -> 1.29 --- Log message: When we code extract some stuff, leave the codeRepl block in the place where the extracted code was, instead of putting it at the end of the function --- Diffs of the changes: (+1 -1) Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp diff -u llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.28 llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.29 --- llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.28 Wed Aug 11 22:17:02 2004 +++ llvm/lib/Transforms/Utils/CodeExtractor.cpp Thu Aug 12 22:17:39 2004 @@ -622,7 +622,7 @@ Function *oldFunction = header->getParent(); // This takes place of the original loop - BasicBlock *codeReplacer = new BasicBlock("codeRepl", oldFunction); + BasicBlock *codeReplacer = new BasicBlock("codeRepl", oldFunction, header); // The new function needs a root node because other nodes can branch to the // head of the region, but the entry node of a function cannot have preds. From lattner at cs.uiuc.edu Thu Aug 12 22:27:20 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 22:27:20 -0500 Subject: [llvm-commits] CVS: llvm/lib/Transforms/Utils/CodeExtractor.cpp Message-ID: <200408130327.WAA31243@apoc.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: CodeExtractor.cpp updated: 1.29 -> 1.30 --- Log message: If we are extracting a block that has multiple successors that are the same block (common in a switch), make sure to remove extra edges in successor blocks. This fixes CodeExtractor/2004-08-12-BlockExtractPHI.ll and should be pulled into LLVM 1.3 (though the regression test need not be, as that would require pulling in the LoopExtract.cpp changes). --- Diffs of the changes: (+11 -2) Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp diff -u llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.29 llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.30 --- llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.29 Thu Aug 12 22:17:39 2004 +++ llvm/lib/Transforms/Utils/CodeExtractor.cpp Thu Aug 12 22:27:07 2004 @@ -657,10 +657,19 @@ succ_end(codeReplacer)); for (unsigned i = 0, e = Succs.size(); i != e; ++i) for (BasicBlock::iterator I = Succs[i]->begin(); - PHINode *PN = dyn_cast(I); ++I) + PHINode *PN = dyn_cast(I); ++I) { + std::set ProcessedPreds; for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) if (BlocksToExtract.count(PN->getIncomingBlock(i))) - PN->setIncomingBlock(i, codeReplacer); + if (ProcessedPreds.insert(PN->getIncomingBlock(i)).second) + PN->setIncomingBlock(i, codeReplacer); + else { + // There were multiple entries in the PHI for this block, now there + // is only one, so remove the duplicated entries. + PN->removeIncomingValue(i, false); + --i; --e; + } + } //std::cerr << "NEW FUNCTION: " << *newFunction; // verifyFunction(*newFunction); From lattner at cs.uiuc.edu Thu Aug 12 22:27:58 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Thu, 12 Aug 2004 22:27:58 -0500 Subject: [llvm-commits] CVS: llvm/test/Regression/Transforms/CodeExtractor/2004-08-12-BlockExtractPHI.ll Message-ID: <200408130327.WAA31258@apoc.cs.uiuc.edu> Changes in directory llvm/test/Regression/Transforms/CodeExtractor: 2004-08-12-BlockExtractPHI.ll updated: 1.1 -> 1.2 --- Log message: Add another test --- Diffs of the changes: (+16 -1) Index: llvm/test/Regression/Transforms/CodeExtractor/2004-08-12-BlockExtractPHI.ll diff -u llvm/test/Regression/Transforms/CodeExtractor/2004-08-12-BlockExtractPHI.ll:1.1 llvm/test/Regression/Transforms/CodeExtractor/2004-08-12-BlockExtractPHI.ll:1.2 --- llvm/test/Regression/Transforms/CodeExtractor/2004-08-12-BlockExtractPHI.ll:1.1 Thu Aug 12 22:08:54 2004 +++ llvm/test/Regression/Transforms/CodeExtractor/2004-08-12-BlockExtractPHI.ll Thu Aug 12 22:27:48 2004 @@ -2,7 +2,7 @@ implementation -void %l102_yyparse() { +void %test1() { no_exit.0.i: br bool false, label %yylex.entry, label %yylex.entry @@ -10,3 +10,18 @@ %tmp.1027 = phi int [ 0, %no_exit.0.i ], [ 0, %no_exit.0.i ] ret void } + +void %test2() { +no_exit.0.i: + switch uint 0, label %yylex.entry [ + uint 0, label %yylex.entry + uint 1, label %foo + ] + +yylex.entry: + %tmp.1027 = phi int [ 0, %no_exit.0.i ], [ 0, %no_exit.0.i ] + ret void +foo: + ret void +} + From natebegeman at mac.com Thu Aug 12 22:57:00 2004 From: natebegeman at mac.com (Nate Begeman) Date: Thu, 12 Aug 2004 22:57:00 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp Message-ID: <200408130357.WAA32589@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC32ISelSimple.cpp updated: 1.60 -> 1.61 --- Log message: Fix llc crasher compiling siod by giving BuildMI the correct number of arguments --- Diffs of the changes: (+1 -1) Index: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp diff -u llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.60 llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.61 --- llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.60 Wed Aug 11 02:40:04 2004 +++ llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp Thu Aug 12 22:56:49 2004 @@ -2797,7 +2797,7 @@ unsigned TempReg2 = makeAnotherReg(DestTy); addFrameReference(BuildMI(*BB, IP, PPC::LBZ, 2, TempReg2), ValueFrameIdx, 7); - BuildMI(*MBB, IP, PPC::EXTSB, DestReg).addReg(TempReg2); + BuildMI(*BB, IP, PPC::EXTSB, 1, DestReg).addReg(TempReg2); } else { int offset = (DestClass == cShort) ? 6 : 4; unsigned LoadOp = (DestClass == cShort) ? PPC::LHA : PPC::LWZ; From natebegeman at mac.com Thu Aug 12 23:45:24 2004 From: natebegeman at mac.com (Nate Begeman) Date: Thu, 12 Aug 2004 23:45:24 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp Message-ID: <200408130445.XAA32728@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC32ISelSimple.cpp updated: 1.61 -> 1.62 --- Log message: Fix 177.mesa compilation, don't use floating point regs for base addresses! --- Diffs of the changes: (+1 -1) Index: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp diff -u llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.61 llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.62 --- llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.61 Thu Aug 12 22:56:49 2004 +++ llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp Thu Aug 12 23:45:14 2004 @@ -1535,7 +1535,7 @@ .addReg(PPC::R1); if (GPR_remaining > 0) { BuildMI(BB, PPC::LWZ, 2, GPR[GPR_idx]) - .addSImm(ArgOffset).addReg(ArgReg); + .addSImm(ArgOffset).addReg(PPC::R1); CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use); } } From natebegeman at mac.com Fri Aug 13 04:32:12 2004 From: natebegeman at mac.com (Nate Begeman) Date: Fri, 13 Aug 2004 04:32:12 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp PPC32AsmPrinter.cpp Message-ID: <200408130932.EAA14685@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC32ISelSimple.cpp updated: 1.62 -> 1.63 PPC32AsmPrinter.cpp updated: 1.34 -> 1.35 --- Log message: Fix siod by switching BoolTy to byte rather than int until CFE changes for Darwin. Also, change asm printer to output proper stubs for external functions whose address is passed as an argument to aid in bugpointing. --- Diffs of the changes: (+28 -27) Index: llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp diff -u llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.62 llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.63 --- llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp:1.62 Thu Aug 12 23:45:14 2004 +++ llvm/lib/Target/PowerPC/PPC32ISelSimple.cpp Fri Aug 13 04:32:01 2004 @@ -68,7 +68,7 @@ // getClassB - Just like getClass, but treat boolean values as ints. static inline TypeClass getClassB(const Type *Ty) { - if (Ty == Type::BoolTy) return cInt; + if (Ty == Type::BoolTy) return cByte; return getClass(Ty); } Index: llvm/lib/Target/PowerPC/PPC32AsmPrinter.cpp diff -u llvm/lib/Target/PowerPC/PPC32AsmPrinter.cpp:1.34 llvm/lib/Target/PowerPC/PPC32AsmPrinter.cpp:1.35 --- llvm/lib/Target/PowerPC/PPC32AsmPrinter.cpp:1.34 Tue Aug 10 19:09:42 2004 +++ llvm/lib/Target/PowerPC/PPC32AsmPrinter.cpp Fri Aug 13 04:32:01 2004 @@ -74,7 +74,7 @@ } void printMachineInstruction(const MachineInstr *MI); - void printOp(const MachineOperand &MO, bool elideOffsetKeyword = false); + void printOp(const MachineOperand &MO, bool LoadAddrOp = false); void printImmOp(const MachineOperand &MO, unsigned ArgType); void printConstantPool(MachineConstantPool *MCP); bool runOnMachineFunction(MachineFunction &F); @@ -401,7 +401,7 @@ } void Printer::printOp(const MachineOperand &MO, - bool elideOffsetKeyword /* = false */) { + bool LoadAddrOp /* = false */) { const MRegisterInfo &RI = *TM.getRegisterInfo(); int new_symbol; @@ -444,31 +444,32 @@ O << MO.getSymbolName(); return; - case MachineOperand::MO_GlobalAddress: - if (!elideOffsetKeyword) { - GlobalValue *GV = MO.getGlobal(); - std::string Name = Mang->getValueName(GV); - - // Dynamically-resolved functions need a stub for the function - Function *F = dyn_cast(GV); - if (F && F->isExternal() && - TM.CalledFunctions.find(F) != TM.CalledFunctions.end()) { - FnStubs.insert(Name); - O << "L" << Name << "$stub"; - return; - } - - // External global variables need a non-lazily-resolved stub - if (!GV->hasInternalLinkage() && - TM.AddressTaken.find(GV) != TM.AddressTaken.end()) { - GVStubs.insert(Name); - O << "L" << Name << "$non_lazy_ptr"; - return; - } + case MachineOperand::MO_GlobalAddress: { + GlobalValue *GV = MO.getGlobal(); + std::string Name = Mang->getValueName(GV); + + // Dynamically-resolved functions need a stub for the function. Be + // wary however not to output $stub for external functions whose addresses + // are taken. Those should be emitted as $non_lazy_ptr below. + Function *F = dyn_cast(GV); + if (F && F->isExternal() && !LoadAddrOp && + TM.CalledFunctions.find(F) != TM.CalledFunctions.end()) { + FnStubs.insert(Name); + O << "L" << Name << "$stub"; + return; + } - O << Mang->getValueName(GV); + // External global variables need a non-lazily-resolved stub + if (!GV->hasInternalLinkage() && + TM.AddressTaken.find(GV) != TM.AddressTaken.end()) { + GVStubs.insert(Name); + O << "L" << Name << "$non_lazy_ptr"; + return; } + + O << Mang->getValueName(GV); return; + } default: O << ""; @@ -548,7 +549,7 @@ if (Opcode == PPC::LOADLoDirect || Opcode == PPC::LOADLoIndirect) { printOp(MI->getOperand(0)); O << ", lo16("; - printOp(MI->getOperand(2)); + printOp(MI->getOperand(2), true /* LoadAddrOp */); O << "-\"L0000" << LabelNumber << "$pb\")"; O << "("; if (MI->getOperand(1).getReg() == PPC::R0) @@ -564,7 +565,7 @@ else printOp(MI->getOperand(1)); O << ", ha16(" ; - printOp(MI->getOperand(2)); + printOp(MI->getOperand(2), true /* LoadAddrOp */); O << "-\"L0000" << LabelNumber << "$pb\")\n"; } else if (ArgCount == 3 && ArgType[1] == PPCII::Disimm16) { printOp(MI->getOperand(0)); From natebegeman at mac.com Fri Aug 13 04:33:28 2004 From: natebegeman at mac.com (Nate Begeman) Date: Fri, 13 Aug 2004 04:33:28 -0500 Subject: [llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC32TargetMachine.h Message-ID: <200408130933.EAA14721@zion.cs.uiuc.edu> Changes in directory llvm/lib/Target/PowerPC: PPC32TargetMachine.h updated: 1.2 -> 1.3 --- Log message: Remove an unneeded header and forward declaration --- Diffs of the changes: (+0 -2) Index: llvm/lib/Target/PowerPC/PPC32TargetMachine.h diff -u llvm/lib/Target/PowerPC/PPC32TargetMachine.h:1.2 llvm/lib/Target/PowerPC/PPC32TargetMachine.h:1.3 --- llvm/lib/Target/PowerPC/PPC32TargetMachine.h:1.2 Wed Aug 11 02:40:04 2004 +++ llvm/lib/Target/PowerPC/PPC32TargetMachine.h Fri Aug 13 04:33:17 2004 @@ -18,11 +18,9 @@ #include "llvm/Target/TargetFrameInfo.h" #include "llvm/PassManager.h" #include "PowerPCTargetMachine.h" -#include namespace llvm { -class GlobalValue; class IntrinsicLowering; class PPC32TargetMachine : public PowerPCTargetMachine { From criswell at cs.uiuc.edu Fri Aug 13 13:52:16 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 13:52:16 -0500 Subject: [llvm-commits] [release_13] CVS: llvm/lib/Transforms/Utils/CodeExtractor.cpp ValueMapper.cpp Message-ID: <200408131852.NAA14776@choi.cs.uiuc.edu> Changes in directory llvm/lib/Transforms/Utils: CodeExtractor.cpp updated: 1.27.2.1 -> 1.27.2.2 ValueMapper.cpp updated: 1.17 -> 1.17.2.1 --- Log message: Merged from mainline. --- Diffs of the changes: (+17 -3) Index: llvm/lib/Transforms/Utils/CodeExtractor.cpp diff -u llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.27.2.1 llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.27.2.2 --- llvm/lib/Transforms/Utils/CodeExtractor.cpp:1.27.2.1 Thu Aug 12 09:28:44 2004 +++ llvm/lib/Transforms/Utils/CodeExtractor.cpp Fri Aug 13 13:52:00 2004 @@ -622,7 +622,7 @@ Function *oldFunction = header->getParent(); // This takes place of the original loop - BasicBlock *codeReplacer = new BasicBlock("codeRepl", oldFunction); + BasicBlock *codeReplacer = new BasicBlock("codeRepl", oldFunction, header); // The new function needs a root node because other nodes can branch to the // head of the region, but the entry node of a function cannot have preds. @@ -657,10 +657,19 @@ succ_end(codeReplacer)); for (unsigned i = 0, e = Succs.size(); i != e; ++i) for (BasicBlock::iterator I = Succs[i]->begin(); - PHINode *PN = dyn_cast(I); ++I) + PHINode *PN = dyn_cast(I); ++I) { + std::set ProcessedPreds; for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) if (BlocksToExtract.count(PN->getIncomingBlock(i))) - PN->setIncomingBlock(i, codeReplacer); + if (ProcessedPreds.insert(PN->getIncomingBlock(i)).second) + PN->setIncomingBlock(i, codeReplacer); + else { + // There were multiple entries in the PHI for this block, now there + // is only one, so remove the duplicated entries. + PN->removeIncomingValue(i, false); + --i; --e; + } + } //std::cerr << "NEW FUNCTION: " << *newFunction; // verifyFunction(*newFunction); Index: llvm/lib/Transforms/Utils/ValueMapper.cpp diff -u llvm/lib/Transforms/Utils/ValueMapper.cpp:1.17 llvm/lib/Transforms/Utils/ValueMapper.cpp:1.17.2.1 --- llvm/lib/Transforms/Utils/ValueMapper.cpp:1.17 Wed Aug 4 03:22:15 2004 +++ llvm/lib/Transforms/Utils/ValueMapper.cpp Fri Aug 13 13:52:00 2004 @@ -81,6 +81,11 @@ for (unsigned i = 1, e = CE->getNumOperands(); i != e; ++i) Idx.push_back(cast(MapValue(CE->getOperand(i), VM))); return VMSlot = ConstantExpr::getGetElementPtr(MV, Idx); + } else if (CE->getOpcode() == Instruction::Select) { + Constant *MV1 = cast(MapValue(CE->getOperand(0), VM)); + Constant *MV2 = cast(MapValue(CE->getOperand(1), VM)); + Constant *MV3 = cast(MapValue(CE->getOperand(2), VM)); + return VMSlot = ConstantExpr::getSelect(MV1, MV2, MV3); } else { assert(CE->getNumOperands() == 2 && "Must be binary operator?"); Constant *MV1 = cast(MapValue(CE->getOperand(0), VM)); From reid at x10sys.com Fri Aug 13 14:47:41 2004 From: reid at x10sys.com (Reid Spencer) Date: Fri, 13 Aug 2004 14:47:41 -0500 Subject: [llvm-commits] CVS: llvm/lib/Support/CommandLine.cpp Message-ID: <200408131947.OAA06725@zion.cs.uiuc.edu> Changes in directory llvm/lib/Support: CommandLine.cpp updated: 1.47 -> 1.48 --- Log message: Allow any cl::opt to use the method getPosition() to retrieve the option's absolute position on the command line. Similarly allow any cl::list to use the method getPosition(n) to retrieve the absolute position of the nth option in the list. This provides support for two things: (a) options like -l that are actually positional and their order of occurrence matters when they are intermixed with positional arguments like "a.o"; and (b) options like -x LANG which affect only the positional arguments that come after the option. In both cases, knowing the absolute position of a given option helps. --- Diffs of the changes: (+32 -19) Index: llvm/lib/Support/CommandLine.cpp diff -u llvm/lib/Support/CommandLine.cpp:1.47 llvm/lib/Support/CommandLine.cpp:1.48 --- llvm/lib/Support/CommandLine.cpp:1.47 Tue Aug 3 19:36:06 2004 +++ llvm/lib/Support/CommandLine.cpp Fri Aug 13 14:47:30 2004 @@ -111,11 +111,12 @@ } // Run the handler now! - return Handler->addOccurrence(ArgName, Value); + return Handler->addOccurrence(i, ArgName, Value); } -static bool ProvidePositionalOption(Option *Handler, const std::string &Arg) { - int Dummy; +static bool ProvidePositionalOption(Option *Handler, const std::string &Arg, + int i) { + int Dummy = i; return ProvideOption(Handler, Handler->ArgStr, Arg.c_str(), 0, 0, Dummy); } @@ -323,10 +324,10 @@ } } - // PositionalVals - A vector of "positional" arguments we accumulate into to - // processes at the end... + // PositionalVals - A vector of "positional" arguments we accumulate into + // the process at the end... // - std::vector PositionalVals; + std::vector > PositionalVals; // If the program has named positional arguments, and the name has been run // across, keep track of which positional argument was named. Otherwise put @@ -347,10 +348,10 @@ if (argv[i][0] != '-' || argv[i][1] == 0 || DashDashFound) { // Positional argument! if (ActivePositionalArg) { - ProvidePositionalOption(ActivePositionalArg, argv[i]); + ProvidePositionalOption(ActivePositionalArg, argv[i], i); continue; // We are done! } else if (!PositionalOpts.empty()) { - PositionalVals.push_back(argv[i]); + PositionalVals.push_back(std::make_pair(argv[i],i)); // All of the positional arguments have been fulfulled, give the rest to // the consume after option... if it's specified... @@ -358,7 +359,7 @@ if (PositionalVals.size() >= NumPositionalRequired && ConsumeAfterOpt != 0) { for (++i; i < argc; ++i) - PositionalVals.push_back(argv[i]); + PositionalVals.push_back(std::make_pair(argv[i],i)); break; // Handle outside of the argument processing loop... } @@ -377,7 +378,7 @@ ArgName = argv[i]+1; Handler = LookupOption(ArgName, Value); if (!Handler || Handler->getFormattingFlag() != cl::Positional) { - ProvidePositionalOption(ActivePositionalArg, argv[i]); + ProvidePositionalOption(ActivePositionalArg, argv[i], i); continue; // We are done! } @@ -479,7 +480,9 @@ unsigned ValNo = 0, NumVals = PositionalVals.size(); for (unsigned i = 0, e = PositionalOpts.size(); i != e; ++i) { if (RequiresValue(PositionalOpts[i])) { - ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo++]); + ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo].first, + PositionalVals[ValNo].second); + ValNo++; --NumPositionalRequired; // We fulfilled our duty... } @@ -495,7 +498,10 @@ // FALL THROUGH case cl::ZeroOrMore: // Zero or more will take all they can get... case cl::OneOrMore: // One or more will take all they can get... - ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo++]); + ProvidePositionalOption(PositionalOpts[i], + PositionalVals[ValNo].first, + PositionalVals[ValNo].second); + ValNo++; break; default: assert(0 && "Internal error, unexpected NumOccurrences flag in " @@ -507,24 +513,31 @@ assert(ConsumeAfterOpt && NumPositionalRequired <= PositionalVals.size()); unsigned ValNo = 0; for (unsigned j = 1, e = PositionalOpts.size(); j != e; ++j) - if (RequiresValue(PositionalOpts[j])) + if (RequiresValue(PositionalOpts[j])) { ErrorParsing |= ProvidePositionalOption(PositionalOpts[j], - PositionalVals[ValNo++]); + PositionalVals[ValNo].first, + PositionalVals[ValNo].second); + ValNo++; + } // Handle the case where there is just one positional option, and it's // optional. In this case, we want to give JUST THE FIRST option to the // positional option and keep the rest for the consume after. The above // loop would have assigned no values to positional options in this case. // - if (PositionalOpts.size() == 2 && ValNo == 0 && !PositionalVals.empty()) + if (PositionalOpts.size() == 2 && ValNo == 0 && !PositionalVals.empty()) { ErrorParsing |= ProvidePositionalOption(PositionalOpts[1], - PositionalVals[ValNo++]); + PositionalVals[ValNo].first, + PositionalVals[ValNo].second); + ValNo++; + } // Handle over all of the rest of the arguments to the // cl::ConsumeAfter command line option... for (; ValNo != PositionalVals.size(); ++ValNo) ErrorParsing |= ProvidePositionalOption(ConsumeAfterOpt, - PositionalVals[ValNo]); + PositionalVals[ValNo].first, + PositionalVals[ValNo].second); } // Loop over args and make sure all required args are specified! @@ -567,7 +580,7 @@ return true; } -bool Option::addOccurrence(const char *ArgName, const std::string &Value) { +bool Option::addOccurrence(unsigned pos, const char *ArgName, const std::string &Value) { NumOccurrences++; // Increment the number of times we have been seen switch (getNumOccurrencesFlag()) { @@ -585,7 +598,7 @@ default: return error(": bad num occurrences flag value!"); } - return handleOccurrence(ArgName, Value); + return handleOccurrence(pos, ArgName, Value); } // addArgument - Tell the system that this Option subclass will handle all From reid at x10sys.com Fri Aug 13 14:47:41 2004 From: reid at x10sys.com (Reid Spencer) Date: Fri, 13 Aug 2004 14:47:41 -0500 Subject: [llvm-commits] CVS: llvm/include/Support/CommandLine.h Message-ID: <200408131947.OAA06722@zion.cs.uiuc.edu> Changes in directory llvm/include/Support: CommandLine.h updated: 1.34 -> 1.35 --- Log message: Allow any cl::opt to use the method getPosition() to retrieve the option's absolute position on the command line. Similarly allow any cl::list to use the method getPosition(n) to retrieve the absolute position of the nth option in the list. This provides support for two things: (a) options like -l that are actually positional and their order of occurrence matters when they are intermixed with positional arguments like "a.o"; and (b) options like -x LANG which affect only the positional arguments that come after the option. In both cases, knowing the absolute position of a given option helps. --- Diffs of the changes: (+34 -24) Index: llvm/include/Support/CommandLine.h diff -u llvm/include/Support/CommandLine.h:1.34 llvm/include/Support/CommandLine.h:1.35 --- llvm/include/Support/CommandLine.h:1.34 Thu Jul 15 19:01:05 2004 +++ llvm/include/Support/CommandLine.h Fri Aug 13 14:47:30 2004 @@ -51,7 +51,7 @@ // Flags permitted to be passed to command line arguments // -enum NumOccurrences { // Flags for the number of occurrences allowed +enum NumOccurrences { // Flags for the number of occurrences allowed Optional = 0x01, // Zero or One occurrence ZeroOrMore = 0x02, // Zero or more occurrences allowed Required = 0x03, // One occurrence required @@ -103,13 +103,13 @@ Positional = 0x080, // Is a positional argument, no '-' required Prefix = 0x100, // Can this option directly prefix its value? Grouping = 0x180, // Can this option group with other options? - FormattingMask = 0x180, + FormattingMask = 0x180, // Union of the above flags. }; -enum MiscFlags { // Miscellaneous flags to adjust argument - CommaSeparated = 0x200, // Should this cl::list split between commas? - PositionalEatsArgs = 0x400, // Should this positional cl::list eat -args? - MiscMask = 0x600, +enum MiscFlags { // Miscellaneous flags to adjust argument + CommaSeparated = 0x200, // Should this cl::list split between commas? + PositionalEatsArgs = 0x400, // Should this positional cl::list eat -args? + MiscMask = 0x600, // Union of the above flags. }; @@ -126,7 +126,8 @@ // an argument. Should return true if there was an error processing the // argument and the program should exit. // - virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) = 0; + virtual bool handleOccurrence(unsigned pos, const char *ArgName, + const std::string &Arg) = 0; virtual enum NumOccurrences getNumOccurrencesFlagDefault() const { return Optional; @@ -141,8 +142,9 @@ return NormalFormatting; } - int NumOccurrences; // The number of times specified + int NumOccurrences; // The number of times specified int Flags; // Flags for the argument + unsigned Position; // Position of last occurrence of the option public: const char *ArgStr; // The argument string itself (ex: "help", "o") const char *HelpStr; // The descriptive text message for --help @@ -171,6 +173,7 @@ inline unsigned getMiscFlags() const { return Flags & MiscMask; } + inline unsigned getPosition() const { return Position; } // hasArgStr - Return true if the argstr != "" bool hasArgStr() const { return ArgStr[0] != 0; } @@ -198,8 +201,9 @@ void setHiddenFlag(enum OptionHidden Val) { setFlag(Val, HiddenMask); } void setFormattingFlag(enum FormattingFlags V) { setFlag(V, FormattingMask); } void setMiscFlag(enum MiscFlags M) { setFlag(M, M); } + void setPosition(unsigned pos) { Position = pos; } protected: - Option() : NumOccurrences(0), Flags(0), + Option() : NumOccurrences(0), Flags(0), Position(0), ArgStr(""), HelpStr(""), ValueStr("") {} public: @@ -219,7 +223,8 @@ // addOccurrence - Wrapper around handleOccurrence that enforces Flags // - bool addOccurrence(const char *ArgName, const std::string &Value); + bool addOccurrence(unsigned pos, const char *ArgName, + const std::string &Value); // Prints option name followed by message. Always returns true. bool error(std::string Message, const char *ArgName = 0); @@ -250,7 +255,6 @@ void apply(Option &O) const { O.setValueStr(Desc); } }; - // init - Specify a default (initial) value for the command line argument, if // the default constructor for the argument type does not give you what you // want. This is only valid on "opt" arguments, not on "list" arguments. @@ -438,7 +442,7 @@ } // parse - Return true on error. - bool parse(Option &O, const char *ArgName, const std::string &Arg, + bool parse(Option &O, const char *ArgName, const std::string &Arg, DataType &V) { std::string ArgVal; if (hasArgStr) @@ -492,7 +496,6 @@ // void printOptionInfo(const Option &O, unsigned GlobalWidth) const; - // getValueName - Overload in subclass to provide a better default value. virtual const char *getValueName() const { return "value"; } }; @@ -545,8 +548,7 @@ struct parser : public basic_parser { // parse - Return true on error. - bool parse(Option &O, const char *ArgName, const std::string &Arg, - unsigned &Val); + bool parse(Option &O, const char *AN, const std::string &Arg, unsigned &Val); // getValueName - Overload in subclass to provide a better default value. virtual const char *getValueName() const { return "uint"; } @@ -585,7 +587,7 @@ template<> struct parser : public basic_parser { // parse - Return true on error. - bool parse(Option &O, const char *ArgName, const std::string &Arg, + bool parse(Option &O, const char *AN, const std::string &Arg, std::string &Value) { Value = Arg; return false; @@ -595,8 +597,6 @@ virtual const char *getValueName() const { return "string"; } }; - - //===----------------------------------------------------------------------===// // applicator class - This class is used because we must use partial // specialization to handle literal string arguments specially (const char* does @@ -728,11 +728,13 @@ is_class::value> { ParserClass Parser; - virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) { + virtual bool handleOccurrence(unsigned pos, const char *ArgName, + const std::string &Arg) { typename ParserClass::parser_data_type Val; if (Parser.parse(*this, ArgName, Arg, Val)) return true; // Parse error! setValue(Val); + setPosition(pos); return false; } @@ -875,6 +877,7 @@ template > class list : public Option, public list_storage { + std::vector Positions; ParserClass Parser; virtual enum NumOccurrences getNumOccurrencesFlagDefault() const { @@ -884,11 +887,14 @@ return Parser.getValueExpectedFlagDefault(); } - virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) { + virtual bool handleOccurrence(unsigned pos, const char *ArgName, + const std::string &Arg) { typename ParserClass::parser_data_type Val; if (Parser.parse(*this, ArgName, Arg, Val)) return true; // Parse Error! addValue(Val); + setPosition(pos); + Positions.push_back(pos); return false; } @@ -905,6 +911,11 @@ public: ParserClass &getParser() { return Parser; } + unsigned getPosition(unsigned optnum) { + assert(optnum < this->size() && "Invalid option index"); + return Positions[optnum]; + } + // One option... template list(const M0t &M0) { @@ -966,16 +977,15 @@ } }; - - //===----------------------------------------------------------------------===// // Aliased command line option (alias this name to a preexisting name) // class alias : public Option { Option *AliasFor; - virtual bool handleOccurrence(const char *ArgName, const std::string &Arg) { - return AliasFor->handleOccurrence(AliasFor->ArgStr, Arg); + virtual bool handleOccurrence(unsigned pos, const char *ArgName, + const std::string &Arg) { + return AliasFor->handleOccurrence(pos, AliasFor->ArgStr, Arg); } // Aliases default to be hidden... virtual enum OptionHidden getOptionHiddenFlagDefault() const {return Hidden;} From reid at x10sys.com Fri Aug 13 15:19:25 2004 From: reid at x10sys.com (Reid Spencer) Date: Fri, 13 Aug 2004 15:19:25 -0500 Subject: [llvm-commits] CVS: llvm/docs/CommandLine.html Message-ID: <200408132019.PAA06840@zion.cs.uiuc.edu> Changes in directory llvm/docs: CommandLine.html updated: 1.24 -> 1.25 --- Log message: Added description of usage of the getPosition() option on cl::opt and cl::list. --- Diffs of the changes: (+60 -2) Index: llvm/docs/CommandLine.html diff -u llvm/docs/CommandLine.html:1.24 llvm/docs/CommandLine.html:1.25 --- llvm/docs/CommandLine.html:1.24 Tue Aug 10 11:38:18 2004 +++ llvm/docs/CommandLine.html Fri Aug 13 15:19:14 2004 @@ -30,6 +30,8 @@

      • Positional Arguments
      • @@ -780,7 +782,7 @@

        Positional arguments are sorted by their order of construction. This means that command line options will be ordered according to how they are listed in a -.cpp file, but will not have an ordering defined if they positional arguments +.cpp file, but will not have an ordering defined if the positional arguments are defined in multiple .cpp files. The fix for this problem is simply to define all of your positional arguments in one .cpp file.

        @@ -826,6 +828,62 @@ +
        +

        Sometimes an option can affect or modify the meaning of another option. For + example, consider gcc's -x LANG option. This tells + gcc to ignore the suffix of subsequent positional arguments and force + the file to be interpreted as if it contained source code in language + LANG. In order to handle this properly , you need to know the + absolute position of each argument, especially those in lists, so their + interaction(s) can be applied correctly. This is also useful for options like + -llibname which is actually a positional argument that starts with + a dash.

        +

        So, generally, the problem is that you have two cl::list variables + that interact in some way. To ensure the correct interaction, you can use the + cl::list::getPosition(optnum) method. This method returns the + absolute position (as found on the command line) of the optnum + item in the cl::list.

        +

        The idiom for usage is like this:

        
        +  static cl::list<std::string> Files(cl::Positional, cl::OneOrMore);
        +  static cl::listlt;std::string> Libraries("l", cl::ZeroOrMore);
        +
        +  int main(int argc, char**argv) {
        +    // ...
        +    std::vector<std::string>::iterator fileIt = Files.begin();
        +    std::vector<std::string>::iterator libIt  = Libraries.begin();
        +    unsigned libPos = 0, filePos = 0;
        +    while ( 1 ) {
        +      if ( libIt != Libraries.end() )
        +        libPos = Libraries.getPosition( libIt - Libraries.begin() );
        +      else
        +        libPos = 0;
        +      if ( fileIt != Files.end() )
        +        filePos = Files.getPosition( fileIt - Files.begin() );
        +      else
        +        filePos = 0;
        +
        +      if ( filePos != 0 && (libPos == 0 || filePos < libPos) ) {
        +        // Source File Is next
        +        ++fileIt;
        +      }
        +      else if ( libPos != 0 && (filePos == 0 || libPos < filePos) ) {
        +        // Library is next
        +        ++libIt;
        +      }
        +      else
        +        break; // we're done with the list
        +    }
        +  }

        +

        Note that, for compatibility reasons, the cl::opt also supports an + unsigned getPosition() option that will provide the absolute position + of that option. You can apply the same approach as above with a + cl::opt and a cl::list option as you can with two lists.

        +
        + + + @@ -1709,7 +1767,7 @@ Chris Lattner
        LLVM Compiler Infrastructure
        - Last modified: $Date: 2004/08/10 16:38:18 $ + Last modified: $Date: 2004/08/13 20:19:14 $ From reid at x10sys.com Fri Aug 13 15:21:32 2004 From: reid at x10sys.com (Reid Spencer) Date: Fri, 13 Aug 2004 15:21:32 -0500 Subject: [llvm-commits] CVS: llvm/tools/llvmc/ConfigData.cpp ConfigData.h Message-ID: <200408132021.PAA06869@zion.cs.uiuc.edu> Changes in directory llvm/tools/llvmc: ConfigData.cpp added (r1.1) ConfigData.h added (r1.1) --- Log message: First version of a utility internal to llvmc that handles the parsing and construction of configuration data for compiler front ends. --- Diffs of the changes: (+499 -0) Index: llvm/tools/llvmc/ConfigData.cpp diff -c /dev/null llvm/tools/llvmc/ConfigData.cpp:1.1 *** /dev/null Fri Aug 13 15:21:32 2004 --- llvm/tools/llvmc/ConfigData.cpp Fri Aug 13 15:21:22 2004 *************** *** 0 **** --- 1,441 ---- + //===- ConfigData.cpp - Configuration Data Mgmt -----------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by Reid Spencer and is distributed under the + // University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file implements the parsing of configuration files for the LLVM Compiler + // Driver (llvmc). + // + //===------------------------------------------------------------------------=== + + #include "ConfigData.h" + #include "CompilerDriver.h" + #include "Support/StringExtras.h" + #include + + using namespace llvm; + + namespace { + + // This array of strings provides the input for ".ll" files (LLVM Assembly) + // to the configuration file parser. This data is just "built-in" to + // llvmc so it doesn't have to be read from a configuration file. + static const char* LL_Data[] = { + "lang.name=LLVM Assembly", + "lang.translator.preprocesses=false", + "lang.translator.optimizes=No", + "lang.translator.groks_dash_O=No", + "lang.preprocessor.needed=0", + "preprocessor.prog=", + "preprocessor.args=", + "translator.prog=llvm-as", + "translator.args=@in@ -o @out@", + "optimizer.prog=opt", + "optimizer.args=@in@ -o @out@", + "assembler.prog=llc", + "assembler.args=@in@ -o @out@", + "linker.prog=llvm-link", + "linker.args=@in@ -o @out@" + }; + + // This array of strings provides the input for ".st" files (Stacker). + static const char* ST_Data[] = { + "lang.name=Stacker", + "lang.translator.preprocesses=false", + "lang.translator.optimizes=true", + "lang.translator.groks_dash_O=0", + "lang.preprocessor.needed=0", + "preprocessor.prog=cp", + "preprocessor.args=@in@ @out@", + "translator.prog=stkrc", + "translator.args=@in@ -o @out@ -S 2048", + "optimizer.prog=opt", + "optimizer.args=@in@ -o @out@", + "assembler.prog=llc", + "assembler.args=@in@ -o @out@", + "linker.prog=llvm-link", + "linker.args=@in@ -o @out@" + }; + + class InputProvider { + public: + virtual bool getLine(std::string& line) = 0; + virtual void error(const std::string& msg) = 0; + virtual bool errorOccurred() = 0; + }; + + class StaticInputProvider : public InputProvider { + public: + StaticInputProvider(const char *data[], size_t count, + const std::string& nam) { + TheData = data; + limit = count; + where = 0; + name = nam; + errCount = 0; + } + virtual ~StaticInputProvider() {} + virtual bool getLine(std::string& line) { + if ( where >= limit ) return false; + line = TheData[where++]; + return true; + } + + virtual void error(const std::string& msg) { + std::cerr << name << ":" << where << ": Error: " << msg << "\n"; + errCount++; + } + + virtual bool errorOccurred() { return errCount > 0; }; + + private: + const char**TheData; + size_t limit; + size_t where; + std::string name; + size_t errCount; + }; + + inline bool recognize(const char*& p, const char*token) { + while (*p == *token && *token != '\0') + ++token, p++; + return *token == '\0' && ((*p == '\0') || ( *p == '.' ) || (*p == '=')); + } + + inline bool getBoolean(const std::string& value) { + switch (value[0]) { + case 't': + case 'T': + case '1': + case 'y': + case 'Y': + return true; + default : + return false; + } + return false; + } + + inline void skipWhitespace( size_t& pos, const std::string& line ) { + while (pos < line.size() && ( + line[pos] == ' ' || // Space + line[pos] == '\t' || // Horizontal Tab + line[pos] == '\n' || // New Line + line[pos] == '\v' || // Vertical Tab + line[pos] == '\f' || // Form Feed + line[pos] == '\r') // Carriate Return + ) + pos++; + } + + inline void parseArgs(CompilerDriver::Action& pat, + const std::string& value, + InputProvider& provider ) + { + const char* p = value.c_str(); + const char* argStart = p; + while (*p != '\0') { + switch (*p) { + case ' ': + if (argStart != p) + pat.args.push_back(std::string(argStart, p-argStart)); + argStart = ++p; + break; + case '@' : + { + if (argStart != p) + pat.args.push_back(std::string(argStart,p-argStart)); + const char* token = ++p; + while (*p != '@' && *p != 0) + p++; + if ( *p != '@' ) { + provider.error("Unterminated substitution token"); + return; + } else { + p++; + bool legal = false; + switch (token[0]) { + case 'i': + if (token[1] == 'n' && token[2] == '@' ) { + pat.inputAt = pat.args.size(); + pat.args.push_back("in"); + legal = true; + argStart = p; + } + break; + case 'o': + if (token[1] == 'u' && token[2] == 't' && token[3] == '@') { + pat.outputAt = pat.args.size(); + pat.args.push_back("out"); + legal = true; + argStart = p; + } + break; + default: + break; + } + if (!legal) { + provider.error("Invalid substitution token"); + return; + } + } + } + break; + default : + p++; + break; + } + } + } + + CompilerDriver::ConfigData* + ParseConfigData(InputProvider& provider) { + std::string line; + CompilerDriver::ConfigData data; + while ( provider.getLine(line) ) { + // Check line length first + size_t lineLen = line.size(); + if (lineLen > 4096) + provider.error("length of input line (" + utostr(lineLen) + + ") is too long"); + + // First, skip whitespace + size_t stPos = 0; + skipWhitespace(stPos, line); + + // See if there's a hash mark. It and everything after it is + // ignored so lets delete that now. + size_t hashPos = line.find('#'); + if (hashPos != std::string::npos) + line.erase(hashPos); + + // Make sure we have something left to parse + if (line.size() == 0) + continue; // ignore full-line comment or whitespace line + + // Find the equals sign + size_t eqPos = line.find('='); + if (eqPos == std::string::npos) + provider.error("Configuration directive is missing an ="); + + // extract the item name + std::string name(line, stPos, eqPos-stPos); + + // directives without names are illegal + if (name.empty()) + provider.error("Configuration directive name is empty"); + + // Skip whitespace in the value + size_t valPos = eqPos + 1; + skipWhitespace(valPos, line); + + // Skip white space at end of value + size_t endPos = line.length() - 1; + while (line[endPos] == ' ') + endPos--; + + // extract the item value + std::string value(line, valPos, endPos-valPos+1); + + // Get the configuration item as a char pointer + const char*p = name.c_str(); + + // Indicate we haven't found an invalid item yet. + bool invalidItem = false; + + // Parse the contents by examining first character and + // using the recognize function strategically + switch (*p++) { + case 'l' : + // could it be "lang." + if (*p == 'a') { // "lang." ? + if (recognize(p,"ang")) { + p++; + switch (*p++) { + case 'n': + if (recognize(p,"ame")) + data.langName = value; + else + invalidItem = true; + break; + case 't': + if (recognize(p,"ranslator")) { + p++; + if (recognize(p,"preprocesses")) + data.TranslatorPreprocesses = getBoolean(value); + else if (recognize(p, "optimizes")) + data.TranslatorOptimizes = getBoolean(value); + else if (recognize(p, "groks_dash_O")) + data.TranslatorGroksDashO = getBoolean(value); + else + invalidItem = true; + } + else + invalidItem = true; + break; + case 'p': + if (recognize(p,"reprocessor")) { + p++; + if (recognize(p,"needed")) { + data.PreprocessorNeeded = getBoolean(value); + } else + invalidItem = true; + } + else + invalidItem = true; + break; + + default: + invalidItem = true; + break; + } + } + } else if (*p == 'i') { // "linker." ? + if (recognize(p,"inker")) { + p++; + if (recognize(p,"prog")) + data.Linker.program = value; + else if (recognize(p,"args")) + parseArgs(data.Linker,value,provider); + else + invalidItem = true; + } + else + invalidItem = true; + } else { + invalidItem = true; + } + break; + + case 'p' : + if (*p == 'r') { // "preprocessor." ? + if (recognize(p, "reprocessor")) { + p++; + if (recognize(p,"prog")) + data.PreProcessor.program = value; + else if (recognize(p,"args")) + parseArgs(data.PreProcessor,value,provider); + else + invalidItem = true; + } else + invalidItem = true; + } else { + invalidItem = true; + } + break; + + case 't' : + if (*p == 'r') { // "translator." ? + if (recognize(p, "ranslator")) { + p++; + if (recognize(p,"prog")) + data.Translator.program = value; + else if (recognize(p,"args")) + parseArgs(data.Translator,value,provider); + else + invalidItem = true; + } else + invalidItem = true; + } else { + invalidItem = true; + } + break; + + case 'o' : + if (*p == 'p') { // "optimizer." ? + if (recognize(p, "ptimizer")) { + p++; + if (recognize(p,"prog")) + data.Optimizer.program = value; + else if (recognize(p,"args")) + parseArgs(data.Optimizer,value,provider); + else + invalidItem = true; + } else + invalidItem = true; + } else { + invalidItem = true; + } + break; + case 'a' : + if (*p == 's') { // "assembler." ? + if (recognize(p, "ssembler")) { + p++; + if (recognize(p,"prog")) + data.Assembler.program = value; + else if (recognize(p,"args")) + parseArgs(data.Assembler,value,provider); + else + invalidItem = true; + } else + invalidItem = true; + } else { + invalidItem = true; + } + break; + } + if (invalidItem) + provider.error("Invalid configuration item: " + line.substr(stPos, eqPos-stPos)); + } + return new CompilerDriver::ConfigData(data); + } + + CompilerDriver::ConfigData* + ReadConfigData(const std::string& ftype) { + if ( ftype == "ll" ) { + StaticInputProvider sip(LL_Data, sizeof(LL_Data)/sizeof(LL_Data[0]), + "LLVM Assembly (internal)"); + return ParseConfigData(sip); + } else if (ftype == "st") { + StaticInputProvider sip(ST_Data, sizeof(ST_Data)/sizeof(ST_Data[0]), + "Stacker (internal)"); + return ParseConfigData(sip); + } + return 0; + } + + } + + LLVMC_ConfigDataProvider::LLVMC_ConfigDataProvider() + : Configurations() + , configDir() + { + Configurations.clear(); + } + + LLVMC_ConfigDataProvider::~LLVMC_ConfigDataProvider() + { + ConfigDataMap::iterator cIt = Configurations.begin(); + while (cIt != Configurations.end()) { + CompilerDriver::ConfigData* cd = cIt->second; + ++cIt; + delete cd; + } + Configurations.clear(); + } + + CompilerDriver::ConfigData* + LLVMC_ConfigDataProvider::ProvideConfigData(const std::string& filetype) { + CompilerDriver::ConfigData* result = 0; + if (!Configurations.empty()) { + ConfigDataMap::iterator cIt = Configurations.find(filetype); + if ( cIt != Configurations.end() ) { + // We found one in the case, return it. + result = cIt->second; + } + } + if (result == 0) { + // The configuration data doesn't exist, we have to go read it. + result = ReadConfigData(filetype); + // If we got one, cache it + if ( result != 0 ) + Configurations.insert(std::make_pair(filetype,result)); + } + return result; // Might return 0 + } + + // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab Index: llvm/tools/llvmc/ConfigData.h diff -c /dev/null llvm/tools/llvmc/ConfigData.h:1.1 *** /dev/null Fri Aug 13 15:21:32 2004 --- llvm/tools/llvmc/ConfigData.h Fri Aug 13 15:21:22 2004 *************** *** 0 **** --- 1,58 ---- + //===- ConfigData.h - Configuration Data Provider ---------------*- C++ -*-===// + // + // The LLVM Compiler Infrastructure + // + // This file was developed by Reid Spencer and is distributed under the + // University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file declares the LLVMC_ConfigDataProvider class which implements the + // generation of ConfigData objects for the CompilerDriver. + // + //===------------------------------------------------------------------------=== + #ifndef LLVM_TOOLS_LLVMC_CONFIGDATA_H + #define LLVM_TOOLS_LLVMC_CONFIGDATA_H + + #include "CompilerDriver.h" + #include + + namespace llvm { + /// This class provides the high level interface to the LLVM Compiler Driver. + /// The driver's purpose is to make it easier for compiler writers and users + /// of LLVM to utilize the compiler toolkits and LLVM toolset by learning only + /// the interface of one program (llvmc). + /// + /// @see llvmc.cpp + /// @brief The interface to the LLVM Compiler Driver. + class LLVMC_ConfigDataProvider : public CompilerDriver::ConfigDataProvider { + /// @name Constructor + /// @{ + public: + LLVMC_ConfigDataProvider(); + virtual ~LLVMC_ConfigDataProvider(); + + /// @name Methods + /// @{ + public: + /// @brief Provide the configuration data to the CompilerDriver. + virtual CompilerDriver::ConfigData* + ProvideConfigData(const std::string& filetype); + + /// @brief Allow the configuration directory to be set + virtual void setConfigDir(const std::string& dirName) { configDir = dirName; } + + /// @} + /// @name Data + /// @{ + private: + /// @brief This type is used internally to hold the configuration data. + typedef hash_map,std::equal_to > ConfigDataMap; + ConfigDataMap Configurations; ///< The cache of configurations + std::string configDir; + /// @} + }; + } + + #endif From reid at x10sys.com Fri Aug 13 15:22:54 2004 From: reid at x10sys.com (Reid Spencer) Date: Fri, 13 Aug 2004 15:22:54 -0500 Subject: [llvm-commits] CVS: llvm/tools/llvmc/CompilerDriver.cpp CompilerDriver.h llvmc.cpp Message-ID: <200408132022.PAA06891@zion.cs.uiuc.edu> Changes in directory llvm/tools/llvmc: CompilerDriver.cpp added (r1.1) CompilerDriver.h updated: 1.1 -> 1.2 llvmc.cpp updated: 1.2 -> 1.3 --- Log message: Additional functionality. This version handles option parsing and parameter subsitution correctly for at least .ll and .st files. There's still a long way to go (i.e. this isn't worth of review yet). --- Diffs of the changes: (+477 -44) Index: llvm/tools/llvmc/CompilerDriver.cpp diff -c /dev/null llvm/tools/llvmc/CompilerDriver.cpp:1.1 *** /dev/null Fri Aug 13 15:22:53 2004 --- llvm/tools/llvmc/CompilerDriver.cpp Fri Aug 13 15:22:43 2004 *************** *** 0 **** --- 1,227 ---- + //===- DriverAction.cpp - Compile Driver Actions ----------------*- C++ -*-===// + // + // + // The LLVM Compiler Infrastructure + // + // This file was developed by Reid Spencer and is distributed under the + // University of Illinois Open Source License. See LICENSE.TXT for details. + // + //===----------------------------------------------------------------------===// + // + // This file implements support for executable actions in the LLVM Compiler + // Driver (llvmc). + // + //===------------------------------------------------------------------------=== + + #include "CompilerDriver.h" + #include + + using namespace llvm; + + namespace { + inline std::string RemoveSuffix(const std::string& fullName) { + size_t dotpos = fullName.rfind('.',fullName.size()); + if ( dotpos == std::string::npos ) return fullName; + return fullName.substr(0, dotpos); + } + + inline std::string GetSuffix(const std::string& fullName) { + size_t dotpos = fullName.rfind('.',fullName.size()); + if ( dotpos = std::string::npos ) return ""; + return fullName.substr(dotpos+1); + } + const char OutputSuffix[] = ".o"; + + } + + + CompilerDriver::CompilerDriver(ConfigDataProvider& confDatProv ) + : cdp(&confDatProv) + , finalPhase(LINKING) + , optLevel(OPT_FAST_COMPILE) + , isDryRun(false) + , isVerbose(false) + , isDebug(false) + , timeActions(false) + , emitRawCode(false) + , emitNativeCode(false) + , machine() + , libPaths() + { + // FIXME: These libraries are platform specific + libPaths.push_back("/lib"); + libPaths.push_back("/usr/lib"); + } + + CompilerDriver::~CompilerDriver() { + cdp = 0; + libPaths.clear(); + } + + void CompilerDriver::error( const std::string& errmsg ) { + std::cerr << "Error: " << errmsg << ".\n"; + exit(1); + } + + CompilerDriver::Action* CompilerDriver::GetAction(ConfigData* cd, + const std::string& input, + const std::string& output, + Phases phase) + { + Action* pat = 0; + switch (phase) { + case PREPROCESSING: pat = &cd->PreProcessor; break; + case TRANSLATION: pat = &cd->Translator; break; + case OPTIMIZATION: pat = &cd->Optimizer; break; + case ASSEMBLY: pat = &cd->Assembler; break; + case LINKING: pat = &cd->Linker; break; + default: + assert(!"Invalid driver phase!"); + break; + } + assert(pat != 0 && "Invalid command pattern"); + Action* a = new Action(*pat); + a->args[pat->inputAt] = input; + a->args[pat->outputAt] = output; + return a; + } + + void CompilerDriver::WriteAction(Action* a) { + std::cerr << a->program; + std::vector::iterator I = a->args.begin(); + while (I != a->args.end()) { + std::cerr << " " + *I; + ++I; + } + std::cerr << "\n"; + } + + void CompilerDriver::DoAction(Action*a) + { + if (isVerbose) + WriteAction(a); + if (!isDryRun) { + std::cerr << "execve(\"" << a->program << "\",[\n"; + std::vector::iterator I = a->args.begin(); + while (I != a->args.end()) { + std::cerr << " \"" << *I << "\",\n"; + ++I; + } + std::cerr << "],ENV);\n"; + } + } + + int CompilerDriver::execute(const InputList& InpList, + const std::string& Output ) { + // Echo the configuration of options if we're running verbose + if (isDebug) + { + std::cerr << "Compiler Driver Options:\n"; + std::cerr << "DryRun = " << isDryRun << "\n"; + std::cerr << "Verbose = " << isVerbose << " \n"; + std::cerr << "TimeActions = " << timeActions << "\n"; + std::cerr << "EmitRawCode = " << emitRawCode << "\n"; + std::cerr << "OutputMachine = " << machine << "\n"; + std::cerr << "EmitNativeCode = " << emitNativeCode << "\n"; + InputList::const_iterator I = InpList.begin(); + while ( I != InpList.end() ) { + std::cerr << "Input: " << I->first << "(" << I->second << ")\n"; + ++I; + } + std::cerr << "Output: " << Output << "\n"; + } + + // If there's no input, we're done. + if (InpList.empty()) + error("Nothing to compile."); + + // If they are asking for linking and didn't provide an output + // file then its an error (no way for us to "make up" a meaningful + // file name based on the various linker input files). + if (finalPhase == LINKING && Output.empty()) + error("An output file name must be specified for linker output"); + + std::vector actions; + + /// PRE-PROCESSING / TRANSLATION / OPTIMIZATION / ASSEMBLY phases + // for each input item + std::vector LinkageItems; + InputList::const_iterator I = InpList.begin(); + while ( I != InpList.end() ) { + // Get the suffix of the file name + std::string suffix = GetSuffix(I->first); + + // If its a library, bytecode file, or object file, save + // it for linking below and short circuit the + // pre-processing/translation/assembly phases + if (I->second.empty() || suffix == "o" || suffix == "bc") { + // We shouldn't get any of these types of files unless we're + // later going to link. Enforce this limit now. + if (finalPhase != LINKING) { + error("Pre-compiled objects found but linking not requested"); + } + LinkageItems.push_back(I->first); + continue; // short circuit remainder of loop + } + + // At this point, we know its something we need to translate + // and/or optimize. See if we can get the configuration data + // for this kind of file. + ConfigData* cd = cdp->ProvideConfigData(I->second); + if (cd == 0) + error(std::string("Files of type '") + I->second + + "' are not recognized." ); + + // We have valid configuration data, now figure out where the output + // of compilation should end up. + std::string OutFile; + if (finalPhase != LINKING) { + if (InpList.size() == 1 && !Output.empty()) + OutFile = Output; + else + OutFile = RemoveSuffix(I->first) + OutputSuffix; + } else { + OutFile = Output; + } + + /// PRE-PROCESSING PHASE + if (finalPhase == PREPROCESSING) { + if (cd->PreProcessor.program.empty()) + error(cd->langName + " does not support pre-processing"); + else + actions.push_back(GetAction(cd,I->first,OutFile,PREPROCESSING)); + } else if (cd->PreprocessorNeeded && !cd->TranslatorPreprocesses) { + if (!cd->PreProcessor.program.empty()) { + actions.push_back(GetAction(cd,I->first,OutFile,PREPROCESSING)); + } + } + + // Short-circuit remaining actions if all they want is pre-processing + if (finalPhase == PREPROCESSING) { ++I; continue; }; + + /// TRANSLATION PHASE + actions.push_back(GetAction(cd,I->first,OutFile,TRANSLATION)); + // Short-circuit remaining actions if all they want is translation + if (finalPhase == TRANSLATION) { ++I; continue; } + + /// OPTIMIZATION PHASE + actions.push_back(GetAction(cd,I->first,OutFile,OPTIMIZATION)); + // Short-circuit remaining actions if all they want is optimization + if (finalPhase == OPTIMIZATION) { ++I; continue; } + + ++I; + } + + /// LINKING PHASE + + /// RUN THE ACTIONS + std::vector::iterator aIter = actions.begin(); + while (aIter != actions.end()) { + DoAction(*aIter); + aIter++; + } + + return 0; + } + + // vim: sw=2 smartindent smarttab tw=80 autoindent expandtab Index: llvm/tools/llvmc/CompilerDriver.h diff -u llvm/tools/llvmc/CompilerDriver.h:1.1 llvm/tools/llvmc/CompilerDriver.h:1.2 --- llvm/tools/llvmc/CompilerDriver.h:1.1 Tue Aug 10 11:29:18 2004 +++ llvm/tools/llvmc/CompilerDriver.h Fri Aug 13 15:22:43 2004 @@ -1,4 +1,4 @@ -//===- CompilerDriver.h - Compiler Driver ---------------------------------===// +//===- CompilerDriver.h - Compiler Driver -----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -11,6 +11,11 @@ // LLVM Compiler Driver program (llvmc). // //===------------------------------------------------------------------------=== +#ifndef LLVM_TOOLS_LLVMC_COMPILERDRIVER_H +#define LLVM_TOOLS_LLVMC_COMPILERDRIVER_H + +#include +#include namespace llvm { /// This class provides the high level interface to the LLVM Compiler Driver. @@ -24,7 +29,6 @@ /// @name Types /// @{ public: - typedef unsigned OptimizationLevel; enum Phases { PREPROCESSING, ///< Source language combining, filtering, substitution TRANSLATION, ///< Translate source -> LLVM bytecode/assembly @@ -34,42 +38,146 @@ }; enum OptimizationLevels { - OPT_NONE, - OPT_FAST_COMPILE, - OPT_SIMPLE, - OPT_AGGRESSIVE, - OPT_LINK_TIME, - OPT_AGGRESSIVE_LINK_TIME + OPT_NONE, ///< Zippo optimizations, nada, nil, none. + OPT_FAST_COMPILE, ///< Optimize to make >compile< go faster + OPT_SIMPLE, ///< Standard/simple optimizations + OPT_AGGRESSIVE, ///< Aggressive optimizations + OPT_LINK_TIME, ///< Aggressive + LinkTime optimizations + OPT_AGGRESSIVE_LINK_TIME ///< Make it go way fast! + }; + + /// This type is the input list to the CompilerDriver. It provides + /// a vector of filename/filetype pairs. The filetype is used to look up + /// the configuration of the actions to be taken by the driver. + /// @brief The Input Data to the execute method + typedef std::vector > InputList; + + /// This type is read from configuration files or otherwise provided to + /// the CompilerDriver through a "ConfigDataProvider". It serves as both + /// the template of what to do and the actual Action to be executed. + /// @brief A structure to hold the action data for a given source + /// language. + struct Action { + std::string program; ///< The program to execve + std::vector args; ///< Arguments to the program + size_t inputAt; ///< Argument index to insert input file + size_t outputAt; ///< Argument index to insert output file + }; + + struct ConfigData { + std::string langName; ///< The name of the source language + bool TranslatorPreprocesses;///< Translator program will pre-process + bool TranslatorOptimizes; ///< Translator program will optimize too + bool TranslatorGroksDashO; ///< Translator understands -O arguments + bool PreprocessorNeeded; ///< Preprocessor is needed for translation + Action PreProcessor; ///< PreProcessor command line + Action Translator; ///< Translator command line + Action Optimizer; ///< Optimizer command line + Action Assembler; ///< Assembler command line + Action Linker; ///< Linker command line + }; + + /// This pure virtual interface class defines the interface between the + /// CompilerDriver and other software that provides ConfigData objects to + /// it. The CompilerDriver must be configured to use an object of this + /// type so it can obtain the configuration data. + /// @see setConfigDataProvider + /// @brief Configuration Data Provider interface + class ConfigDataProvider { + public: + virtual ConfigData* ProvideConfigData(const std::string& filetype) = 0; + virtual void setConfigDir(const std::string& dirName) = 0; }; /// @} /// @name Constructors /// @{ public: - CompilerDriver(); + CompilerDriver(ConfigDataProvider& cdp ); + virtual ~CompilerDriver(); /// @} - /// @name Accessors + /// @name Methods /// @{ public: - void execute(); ///< Execute the actions requested + /// @brief Handle an error + virtual void error(const std::string& errmsg); + + /// @brief Execute the actions requested for the given input list. + virtual int execute(const InputList& list, const std::string& output); /// @} /// @name Mutators /// @{ public: + /// @brief Set the final phase at which compilation terminates + void setFinalPhase( Phases phase ) { finalPhase = phase; } + /// @brief Set the optimization level for the compilation - void setOptimization( OptimizationLevel level ); - void setFinalPhase( Phases phase ); + void setOptimization( OptimizationLevels level ) { optLevel = level; } + + /// @brief Prevent the CompilerDriver from taking any actions + void setDryRun( bool TF ) { isDryRun = TF; } + + /// @brief Cause the CompilerDriver to print to stderr all the + /// actions it is taking. + void setVerbose( bool TF ) { isVerbose = TF; } + + /// @brief Cause the CompilerDriver to print to stderr very verbose + /// information that might be useful in debugging the driver's actions + void setDebug( bool TF ) { isDebug = TF; } + + /// @brief Cause the CompilerDriver to print to stderr the + /// execution time of each action taken. + void setTimeActions( bool TF ) { timeActions = TF; } + + /// @brief Indicate that native code is to be generated instead + /// of LLVM bytecode. + void setEmitNativeCode( bool TF ) { emitNativeCode = TF; } + + /// @brief Indicate that raw, unoptimized code is to be generated. + void setEmitRawCode(bool TF ) { emitRawCode = TF; } + + /// @brief Set the output machine name. + void setOutputMachine( const std::string& machineName ) { + machine = machineName; + } + + /// @brief Set the list of library paths to be searched for + /// libraries. + void addLibraryPath( const std::string& libPath ) { + libPaths.push_back(libPath); + } + + /// @} + /// @name Functions + /// @{ + private: + Action* GetAction(ConfigData* cd, const std::string& input, + const std::string& output, Phases phase ); + void WriteAction(Action* a); + void DoAction(Action* a); /// @} /// @name Data /// @{ - public: - Phases finalPhase; - OptimizationLevel optLevel; + private: + ConfigDataProvider* cdp; ///< Where we get configuration data from + Phases finalPhase; ///< The final phase of compilation + OptimizationLevels optLevel; ///< The optimization level to apply + bool isDryRun; ///< Prevent actions ? + bool isVerbose; ///< Print actions? + bool isDebug; ///< Print lotsa debug info? + bool timeActions; ///< Time the actions executed ? + bool emitRawCode; ///< Emit Raw (unoptimized) code? + bool emitNativeCode; ///< Emit native code instead of bytecode? + std::string machine; ///< Target machine name + std::vector libPaths; ///< list of dirs to find libraries /// @} }; } + +// vim: sw=2 smartindent smarttab tw=80 autoindent expandtab +#endif Index: llvm/tools/llvmc/llvmc.cpp diff -u llvm/tools/llvmc/llvmc.cpp:1.2 llvm/tools/llvmc/llvmc.cpp:1.3 --- llvm/tools/llvmc/llvmc.cpp:1.2 Tue Aug 10 11:29:18 2004 +++ llvm/tools/llvmc/llvmc.cpp Fri Aug 13 15:22:43 2004 @@ -1,8 +1,8 @@ -//===--- llvmc.cpp - The LLVM Compiler Driver -----------------------------===// +//===--- llvmc.cpp - The LLVM Compiler Driver -------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // -// This file was developed by Reid Spencerand is distributed under the +// This file was developed by Reid Spencer and is distributed under the // University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// @@ -15,24 +15,29 @@ //===------------------------------------------------------------------------=== #include "CompilerDriver.h" +#include "ConfigData.h" #include "llvm/System/Signals.h" #include "Support/CommandLine.h" #include using namespace llvm; +namespace { //===------------------------------------------------------------------------=== //=== PHASE OPTIONS //===------------------------------------------------------------------------=== static cl::opt FinalPhase( cl::desc("Choose final phase of compilation:"), + cl::init(CompilerDriver::LINKING), cl::values( clEnumValN(CompilerDriver::PREPROCESSING,"E", - "Stop compilation after pre-processing"), + "Stop compilation after pre-processing phase"), + clEnumValN(CompilerDriver::TRANSLATION, "t", + "Stop compilation after translation phase"), clEnumValN(CompilerDriver::OPTIMIZATION,"c", - "Stop compilation after source code translation and optimization"), + "Stop compilation after optimization phase"), clEnumValN(CompilerDriver::ASSEMBLY,"S", - "Stop compilation after assembly"), + "Stop compilation after assembly phase"), clEnumValEnd ) ); @@ -42,9 +47,10 @@ //===------------------------------------------------------------------------=== static cl::opt OptLevel( cl::desc("Choose level of optimization to apply:"), + cl::init(CompilerDriver::OPT_FAST_COMPILE), cl::values( clEnumValN(CompilerDriver::OPT_FAST_COMPILE,"O0", - "Optimize for compilation speed, not execution speed."), + "An alias for the -O1 option."), clEnumValN(CompilerDriver::OPT_FAST_COMPILE,"O1", "Optimize for compilation speed, not execution speed."), clEnumValN(CompilerDriver::OPT_SIMPLE,"O2", @@ -64,16 +70,20 @@ //===------------------------------------------------------------------------=== static cl::opt PPToolOpts("Tpp", cl::ZeroOrMore, - cl::desc("Pass specific options to the pre-processor")); + cl::desc("Pass specific options to the pre-processor"), + cl::value_desc("option")); static cl::opt AsmToolOpts("Tasm", cl::ZeroOrMore, - cl::desc("Pass specific options to the assembler")); + cl::desc("Pass specific options to the assembler"), + cl::value_desc("option")); static cl::opt OptToolOpts("Topt", cl::ZeroOrMore, - cl::desc("Pass specific options to the optimizer")); + cl::desc("Pass specific options to the optimizer"), + cl::value_desc("option")); static cl::opt LinkToolOpts("Tlink", cl::ZeroOrMore, - cl::desc("Pass specific options to the linker")); + cl::desc("Pass specific options to the linker"), + cl::value_desc("option")); //===------------------------------------------------------------------------=== //=== INPUT OPTIONS @@ -90,40 +100,47 @@ //=== OUTPUT OPTIONS //===------------------------------------------------------------------------=== -static cl::opt OutputFilename("o", cl::init("a.out"), +static cl::opt OutputFilename("o", cl::desc("Override output filename"), cl::value_desc("filename")); -static cl::opt OutputMachne("m", cl::Prefix, +static cl::opt OutputMachine("m", cl::Prefix, cl::desc("Specify a target machine"), cl::value_desc("machine")); -static cl::opt Native("native", +static cl::opt Native("native", cl::init(false), cl::desc("Generative native object and executables instead of bytecode")); //===------------------------------------------------------------------------=== //=== INFORMATION OPTIONS //===------------------------------------------------------------------------=== -static cl::opt NoOperation("no-operation", cl::Optional, - cl::desc("Do not perform actions")); +static cl::opt DryRun("dry-run", cl::Optional, cl::init(false), + cl::desc("Do everything but perform the compilation actions")); -static cl::alias NoOp("n", cl::Optional, - cl::desc("Alias for -no-operation"), cl::aliasopt(NoOperation)); +static cl::alias DryRunAlias("y", cl::Optional, + cl::desc("Alias for -dry-run"), cl::aliasopt(DryRun)); -static cl::opt Verbose("verbose", cl::Optional, +static cl::opt Verbose("verbose", cl::Optional, cl::init(false), cl::desc("Print out each action taken")); -static cl::alias VerboseAlias("v", cl::Optional, +static cl::alias VerboseAlias("v", cl::Optional, cl::desc("Alias for -verbose"), cl::aliasopt(Verbose)); -static cl::opt TimeActions("time-actions", cl::Optional, +static cl::opt Debug("debug", cl::Optional, cl::init(false), + cl::Hidden, cl::desc("Print out debugging information")); + +static cl::alias DebugAlias("d", cl::Optional, + cl::desc("Alias for -debug"), cl::aliasopt(Debug)); + +static cl::opt TimeActions("time-actions", cl::Optional, cl::init(false), cl::desc("Print execution time for each action taken")); //===------------------------------------------------------------------------=== //=== ADVANCED OPTIONS //===------------------------------------------------------------------------=== -static cl::list ConfigFiles("config-dir", cl::Optional, - cl::desc("Specify a configuration directory to override defaults")); +static cl::opt ConfigDir("config-dir", cl::Optional, + cl::desc("Specify a configuration directory to override defaults"), + cl::value_desc("directory")); static cl::opt EmitRawCode("emit-raw-code", cl::Hidden, cl::desc("Emit raw, unoptimized code")); @@ -133,7 +150,37 @@ //===------------------------------------------------------------------------=== static cl::list Files(cl::Positional, cl::OneOrMore, - cl::desc("Source and object files")); + cl::desc("[Sources/objects/libraries]")); + +static cl::list Languages("x", cl::ZeroOrMore, + cl::desc("Specify the source language for subsequent files"), + cl::value_desc("language")); + +//===------------------------------------------------------------------------=== +//=== GetFileType - determine type of a file +//===------------------------------------------------------------------------=== +const std::string GetFileType(const std::string& fname, unsigned pos ) { + static std::vector::iterator langIt = Languages.begin(); + static std::string CurrLang = ""; + + // If a -x LANG option has been specified .. + if ( langIt != Languages.end() ) + // If the -x LANG option came before the current file on command line + if ( Languages.getPosition( langIt - Languages.begin() ) < pos ) { + // use that language + CurrLang = *langIt++; + return CurrLang; + } + + // If there's a current language in effect + if (!CurrLang.empty()) + return CurrLang; // use that language + + // otherwise just determine lang from the filename's suffix + return fname.substr( fname.rfind('.',fname.size()) + 1 ); +} + +} // end anonymous namespace /// @brief The main program for llvmc @@ -148,14 +195,66 @@ " and source language compiler tools.\n" ); + // Deal with unimplemented options. + if (Native) + std::cerr << argv[0] << ": Not implemented yet: -native"; + if (EmitRawCode) + std::cerr << argv[0] << ": Not implemented yet: -emit-raw-code"; + + // Default the output file, only if we're going to try to link + if (OutputFilename.empty() && OptLevel == CompilerDriver::LINKING) + OutputFilename = "a.out"; + + // Construct the ConfigDataProvider object + LLVMC_ConfigDataProvider Provider; + // Construct the CompilerDriver object - //CompilerDriver CD; + CompilerDriver CD(Provider); + + // Configure the driver based on options + CD.setVerbose(Verbose); + CD.setDebug(Debug); + CD.setDryRun(DryRun); + CD.setFinalPhase(FinalPhase); + CD.setOptimization(OptLevel); + CD.setOutputMachine(OutputMachine); + CD.setEmitNativeCode(Native); + CD.setEmitRawCode(EmitRawCode); + std::vector::iterator pathIt = LibPaths.begin(); + while ( pathIt != LibPaths.end() ) { + CD.addLibraryPath( *pathIt++ ); + } - // Set the options for the Compiler Driver + // Prepare the list of files to be compiled by the CompilerDriver. + CompilerDriver::InputList InpList; + std::vector::iterator fileIt = Files.begin(); + std::vector::iterator libIt = Libraries.begin(); + unsigned libPos = 0, filePos = 0; + while ( 1 ) { + if ( libIt != Libraries.end() ) + libPos = Libraries.getPosition( libIt - Libraries.begin() ); + else + libPos = 0; + if ( fileIt != Files.end() ) + filePos = Files.getPosition( fileIt - Files.begin() ); + else + filePos = 0; + + if ( filePos != 0 && (libPos == 0 || filePos < libPos) ) { + // Add a source file + InpList.push_back( std::make_pair(*fileIt, GetFileType(*fileIt,filePos))); + ++fileIt; + } + else if ( libPos != 0 && (filePos == 0 || libPos < filePos) ) { + // Add a library + InpList.push_back( std::make_pair(*libIt++,"")); + } + else + break; // we're done with the list + } // Tell the driver to do its thing - int result = 0; - // result = CD.execute(); + int result = CD.execute(InpList,OutputFilename); if (result != 0) { std::cerr << argv[0] << ": Error executing actions. Terminated.\n"; return result; @@ -164,4 +263,3 @@ // All is good, return success return 0; } - From reid at x10sys.com Fri Aug 13 15:26:04 2004 From: reid at x10sys.com (Reid Spencer) Date: Fri, 13 Aug 2004 15:26:04 -0500 Subject: [llvm-commits] CVS: llvm/tools/llvmc/CompilerDriver.cpp Message-ID: <200408132026.PAA06921@zion.cs.uiuc.edu> Changes in directory llvm/tools/llvmc: CompilerDriver.cpp updated: 1.1 -> 1.2 --- Log message: Fix header commentary. --- Diffs of the changes: (+2 -3) Index: llvm/tools/llvmc/CompilerDriver.cpp diff -u llvm/tools/llvmc/CompilerDriver.cpp:1.1 llvm/tools/llvmc/CompilerDriver.cpp:1.2 --- llvm/tools/llvmc/CompilerDriver.cpp:1.1 Fri Aug 13 15:22:43 2004 +++ llvm/tools/llvmc/CompilerDriver.cpp Fri Aug 13 15:25:54 2004 @@ -1,4 +1,4 @@ -//===- DriverAction.cpp - Compile Driver Actions ----------------*- C++ -*-===// +//===- CompilerDriver.cpp - The LLVM Compiler Driver ------------*- C++ -*-===// // // // The LLVM Compiler Infrastructure @@ -8,8 +8,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements support for executable actions in the LLVM Compiler -// Driver (llvmc). +// This file implements the bulk of the LLVM Compiler Driver (llvmc). // //===------------------------------------------------------------------------=== From lattner at cs.uiuc.edu Fri Aug 13 16:09:00 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 13 Aug 2004 16:09:00 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/announcement.txt Message-ID: <200408132109.QAA25984@apoc.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3: announcement.txt updated: 1.1 -> 1.2 --- Log message: Write the announcement --- Diffs of the changes: (+57 -17) Index: llvm-www/releases/1.3/announcement.txt diff -u llvm-www/releases/1.3/announcement.txt:1.1 llvm-www/releases/1.3/announcement.txt:1.2 --- llvm-www/releases/1.3/announcement.txt:1.1 Thu Aug 5 15:03:53 2004 +++ llvm-www/releases/1.3/announcement.txt Fri Aug 13 16:08:49 2004 @@ -5,36 +5,76 @@ Infrastructure. If you are new to LLVM, please see "WHAT IS LLVM?" below. If you are already familiar with LLVM, skip to "WHAT IS NEW IN LLVM 1.3?" + WHAT IS LLVM? - LLVM is a new infrastructure designed for compile-time, link-time, runtime, - and "idle-time" optimization of programs from arbitrary programming languages. - LLVM is written in C++ and has been developed over the past 4 years at the - University of Illinois. It currently supports compilation of C and C++ - programs using front-ends derived from GCC 3.4. After optimization, it can - emit native X86, native SparcV9, or C code for the optimized program. New - front-ends are in early development for Java bytecode and CAML, and new - backends are in early development for several other targets. + LLVM is a set of libraries and tools that make it easy to build compilers, + optimizers, Just-In-Time code generators, and many other compiler-related + programs. As examples, LLVM includes C, C++, and Stacker compilers, that use + the components to build aggressively optimizing compilers. LLVM can compile + code to X86, SparcV9, PowerPC (beta support), or C code. Alternatively, LLVM + can JIT compiler code for X86 and SparcV9. + + The strengths of LLVM are its extremely simple design (which makes it easy to + understand and use), source-language independence, powerful mid-level + optimizer, extensibility, and its stability and reliability. The LLVM infrastructure is publicly available under a non-restrictive open source license. More information about LLVM and the contents of the publicly released software is available at the LLVM Web site above. + WHAT IS NEW IN LLVM 1.3? - This release is substantially faster and introduces several new features, - including: new optimizations, support for several GCC extensions that were not - supported in 1.1, and support for profile-guided optimization. The X86 code - generator in LLVM 1.3 also produces much better native code, and LLVM now - comes with a beta-quality global register allocator. Finally, LLVM 1.3 - includes the usual collection of bug fixes and other minor improvements. + This release takes less time to produce faster compiled code, and is portable + to new targets (including Cygwin). It also includes several new features, + such as man pages for all LLVM tools, accurate garbage collection, some new + loop transformations, and includes beta support for powerpc code generation. + LLVM 1.3 also includes the following major improvements: + + Core improvements: + * A new "select" instruction provides efficient conditional move support. + * Accurate garbage collection is fully supported by all code generators. + * LLVM now supports structures with more than 256 elements in them. + * The bytecode file format is now documented. + * Man pages are available for all LLVM tools. + * LLVM now supports unordered floating point comparisons. + + Optimization improvements: + * The induction variable analysis routines are much more aggressive. + * The -indvars pass implements linear function test replacement and exit + value substitution. + * LLVM now include a context-senstitive alias analysis for global variables. + * LLVM includes an implementation of Andersen's alias analysis. + * LLVM includes new loop unrolling and loop unswitching passes. + * LLVM includes a simple dead store elimination pass. + + Code generator improvements: + * The native code generators now default to a global register allocator. + * LLVM includes a new "skeleton" code generator. + * LLC and LLI can load code generators from .so files with the -load option. + * More code generator components are autogenerated from the abstract target + description. + * The X86 backend now generates substantially better code in many cases. + + Other improvements: + * Bugpoint can now debug arbitrary modes of the LLC and LLI tools. + * Bugpoint can now narrow down codegen miscompilations to the basic block + being miscompiled (in many cases). + * Bugpoint can now debug infinite-loop inducing miscompilations. + + Finally, LLVM 1.3 includes the usual collection of bug fixes and other minor + improvements. A full list of new features and bug-fixes are listed in the Release Notes: http://llvm.cs.uiuc.edu/releases/1.3/docs/ReleaseNotes.html#whatsnew - For an easier to read set of changes, please see the status updates: - http://mail.cs.uiuc.edu/pipermail/llvm-announce/2004-March/000006.html - http://mail.cs.uiuc.edu/pipermail/llvm-announce/2004-February/000005.html + For an easier to read (and more details) list of changes, please see the + status updates: + http://mail.cs.uiuc.edu/pipermail/llvm-announce/2004-May/000008.html + http://mail.cs.uiuc.edu/pipermail/llvm-announce/2004-June/000009.html + http://mail.cs.uiuc.edu/pipermail/llvm-announce/2004-July/000010.html + HOW DO I GET IT? From criswell at cs.uiuc.edu Fri Aug 13 16:18:00 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 16:18:00 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/announcement.txt Message-ID: <200408132118.QAA01467@choi.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3: announcement.txt updated: 1.2 -> 1.3 --- Log message: Typo fixes. --- Diffs of the changes: (+7 -6) Index: llvm-www/releases/1.3/announcement.txt diff -u llvm-www/releases/1.3/announcement.txt:1.2 llvm-www/releases/1.3/announcement.txt:1.3 --- llvm-www/releases/1.3/announcement.txt:1.2 Fri Aug 13 16:08:49 2004 +++ llvm-www/releases/1.3/announcement.txt Fri Aug 13 16:17:49 2004 @@ -10,7 +10,7 @@ LLVM is a set of libraries and tools that make it easy to build compilers, optimizers, Just-In-Time code generators, and many other compiler-related - programs. As examples, LLVM includes C, C++, and Stacker compilers, that use + programs. As examples, LLVM includes C, C++, and Stacker compilers that use the components to build aggressively optimizing compilers. LLVM can compile code to X86, SparcV9, PowerPC (beta support), or C code. Alternatively, LLVM can JIT compiler code for X86 and SparcV9. @@ -26,7 +26,7 @@ WHAT IS NEW IN LLVM 1.3? - This release takes less time to produce faster compiled code, and is portable + This release takes less time to produce faster compiled code and is portable to new targets (including Cygwin). It also includes several new features, such as man pages for all LLVM tools, accurate garbage collection, some new loop transformations, and includes beta support for powerpc code generation. @@ -44,7 +44,8 @@ * The induction variable analysis routines are much more aggressive. * The -indvars pass implements linear function test replacement and exit value substitution. - * LLVM now include a context-senstitive alias analysis for global variables. + * LLVM now includes a context-senstitive alias analysis for global + variables. * LLVM includes an implementation of Andersen's alias analysis. * LLVM includes new loop unrolling and loop unswitching passes. * LLVM includes a simple dead store elimination pass. @@ -59,8 +60,8 @@ Other improvements: * Bugpoint can now debug arbitrary modes of the LLC and LLI tools. - * Bugpoint can now narrow down codegen miscompilations to the basic block - being miscompiled (in many cases). + * Bugpoint can now narrow down code generation miscompilations to the basic + block being miscompiled (in many cases). * Bugpoint can now debug infinite-loop inducing miscompilations. Finally, LLVM 1.3 includes the usual collection of bug fixes and other minor @@ -69,7 +70,7 @@ A full list of new features and bug-fixes are listed in the Release Notes: http://llvm.cs.uiuc.edu/releases/1.3/docs/ReleaseNotes.html#whatsnew - For an easier to read (and more details) list of changes, please see the + For an easier to read (and more detailed) list of changes, please see the status updates: http://mail.cs.uiuc.edu/pipermail/llvm-announce/2004-May/000008.html http://mail.cs.uiuc.edu/pipermail/llvm-announce/2004-June/000009.html From lattner at cs.uiuc.edu Fri Aug 13 16:21:11 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 13 Aug 2004 16:21:11 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/announcement.txt Message-ID: <200408132121.QAA26193@apoc.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3: announcement.txt updated: 1.3 -> 1.4 --- Log message: Other minor tweaks --- Diffs of the changes: (+2 -3) Index: llvm-www/releases/1.3/announcement.txt diff -u llvm-www/releases/1.3/announcement.txt:1.3 llvm-www/releases/1.3/announcement.txt:1.4 --- llvm-www/releases/1.3/announcement.txt:1.3 Fri Aug 13 16:17:49 2004 +++ llvm-www/releases/1.3/announcement.txt Fri Aug 13 16:21:01 2004 @@ -10,7 +10,7 @@ LLVM is a set of libraries and tools that make it easy to build compilers, optimizers, Just-In-Time code generators, and many other compiler-related - programs. As examples, LLVM includes C, C++, and Stacker compilers that use + programs. As examples, LLVM includes C, C++, and Stacker compilers which use the components to build aggressively optimizing compilers. LLVM can compile code to X86, SparcV9, PowerPC (beta support), or C code. Alternatively, LLVM can JIT compiler code for X86 and SparcV9. @@ -44,8 +44,7 @@ * The induction variable analysis routines are much more aggressive. * The -indvars pass implements linear function test replacement and exit value substitution. - * LLVM now includes a context-senstitive alias analysis for global - variables. + * LLVM includes a context-senstitive alias analysis for global variables. * LLVM includes an implementation of Andersen's alias analysis. * LLVM includes new loop unrolling and loop unswitching passes. * LLVM includes a simple dead store elimination pass. From lattner at cs.uiuc.edu Fri Aug 13 16:24:22 2004 From: lattner at cs.uiuc.edu (Chris Lattner) Date: Fri, 13 Aug 2004 16:24:22 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/announcement.txt Message-ID: <200408132124.QAA26286@apoc.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3: announcement.txt updated: 1.4 -> 1.5 --- Log message: Minor fix --- Diffs of the changes: (+1 -1) Index: llvm-www/releases/1.3/announcement.txt diff -u llvm-www/releases/1.3/announcement.txt:1.4 llvm-www/releases/1.3/announcement.txt:1.5 --- llvm-www/releases/1.3/announcement.txt:1.4 Fri Aug 13 16:21:01 2004 +++ llvm-www/releases/1.3/announcement.txt Fri Aug 13 16:24:12 2004 @@ -66,7 +66,7 @@ Finally, LLVM 1.3 includes the usual collection of bug fixes and other minor improvements. - A full list of new features and bug-fixes are listed in the Release Notes: + A full list of new features and bug-fixes are listed in the release notes: http://llvm.cs.uiuc.edu/releases/1.3/docs/ReleaseNotes.html#whatsnew For an easier to read (and more detailed) list of changes, please see the From criswell at cs.uiuc.edu Fri Aug 13 16:59:02 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 16:59:02 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/cfrontend-1.3.i686-redhat-linux-gnu.tar.gz cfrontend-1.3.powerpc-apple-darwin7.4.0.tar.gz cfrontend-1.3.source.tar.gz cfrontend-1.3.sparc-sun-solaris2.8.tar.gz llvm-1.3.tar.gz Message-ID: <200408132159.QAA09253@choi.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3: cfrontend-1.3.i686-redhat-linux-gnu.tar.gz added (r1.1) cfrontend-1.3.powerpc-apple-darwin7.4.0.tar.gz added (r1.1) cfrontend-1.3.source.tar.gz added (r1.1) cfrontend-1.3.sparc-sun-solaris2.8.tar.gz added (r1.1) llvm-1.3.tar.gz added (r1.1) --- Log message: Initial commit of LLVM 1.3. --- Diffs of the changes: (+0 -0) Index: llvm-www/releases/1.3/cfrontend-1.3.i686-redhat-linux-gnu.tar.gz Index: llvm-www/releases/1.3/cfrontend-1.3.powerpc-apple-darwin7.4.0.tar.gz Index: llvm-www/releases/1.3/cfrontend-1.3.source.tar.gz Index: llvm-www/releases/1.3/cfrontend-1.3.sparc-sun-solaris2.8.tar.gz Index: llvm-www/releases/1.3/llvm-1.3.tar.gz From criswell at cs.uiuc.edu Fri Aug 13 17:01:32 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 17:01:32 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/docs/ Message-ID: <200408132201.RAA09293@choi.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3/docs: --- Log message: Directory /home/vadve/shared/InternalCVS/llvm-www/releases/1.3/docs added to the repository --- Diffs of the changes: (+0 -0) From criswell at cs.uiuc.edu Fri Aug 13 17:02:22 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 17:02:22 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/docs/CommandGuide/ Message-ID: <200408132202.RAA09325@choi.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3/docs/CommandGuide: --- Log message: Directory /home/vadve/shared/InternalCVS/llvm-www/releases/1.3/docs/CommandGuide added to the repository --- Diffs of the changes: (+0 -0) From criswell at cs.uiuc.edu Fri Aug 13 17:02:22 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 17:02:22 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/docs/img/ Message-ID: <200408132202.RAA09322@choi.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3/docs/img: --- Log message: Directory /home/vadve/shared/InternalCVS/llvm-www/releases/1.3/docs/img added to the repository --- Diffs of the changes: (+0 -0) From criswell at cs.uiuc.edu Fri Aug 13 17:03:15 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 17:03:15 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/docs/AliasAnalysis.html Bugpoint.html BytecodeFormat.html CFEBuildInstrs.html CodeGenerator.html CodingStandards.html CommandLine.html ExtendingLLVM.html FAQ.html GarbageCollection.html GettingStarted.html HowToSubmitABug.html index.html LangRef.html LLVMVsTheWorld.html ObjectFiles.html OpenProjects.html ProgrammersManual.html Projects.html ReleaseNotes.html SourceLevelDebugging.html Stacker.html SystemLibrary.html TableGenFundamentals.html TestingGuide.html WritingAnLLVMPass.html Message-ID: <200408132203.RAA09399@choi.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3/docs: AliasAnalysis.html added (r1.1) Bugpoint.html added (r1.1) BytecodeFormat.html added (r1.1) CFEBuildInstrs.html added (r1.1) CodeGenerator.html added (r1.1) CodingStandards.html added (r1.1) CommandLine.html added (r1.1) ExtendingLLVM.html added (r1.1) FAQ.html added (r1.1) GarbageCollection.html added (r1.1) GettingStarted.html added (r1.1) HowToSubmitABug.html added (r1.1) index.html added (r1.1) LangRef.html added (r1.1) LLVMVsTheWorld.html added (r1.1) ObjectFiles.html added (r1.1) OpenProjects.html added (r1.1) ProgrammersManual.html added (r1.1) Projects.html added (r1.1) ReleaseNotes.html added (r1.1) SourceLevelDebugging.html added (r1.1) Stacker.html added (r1.1) SystemLibrary.html added (r1.1) TableGenFundamentals.html added (r1.1) TestingGuide.html added (r1.1) WritingAnLLVMPass.html added (r1.1) --- Log message: Initial commit of LLVM docs to web. --- Diffs of the changes: (+21194 -0) Index: llvm-www/releases/1.3/docs/AliasAnalysis.html diff -c /dev/null llvm-www/releases/1.3/docs/AliasAnalysis.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/AliasAnalysis.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,956 ---- + + + + LLVM Alias Analysis Infrastructure + + + + +
        + LLVM Alias Analysis Infrastructure +
        + +
          +
        1. Introduction
        2. + +
        3. AliasAnalysis Class Overview + +
        4. + +
        5. Writing a new AliasAnalysis Implementation + +
        6. + +
        7. Using alias analysis results + +
        8. + +
        9. Existing alias analysis implementations and clients + +
        10. +
        + +
        +

        Written by Chris Lattner

        +
        + + + + + +
        + +

        Alias Analysis (aka Pointer Analysis) is a class of techniques which attempt + to determine whether or not two pointers ever can point to the same object in + memory. There are many different algorithms for alias analysis and many + different ways of classifying them: flow-sensitive vs flow-insensitive, + context-sensitive vs context-insensitive, field-sensitive vs field-insensitive, + unification-based vs subset-based, etc. Traditionally, alias analyses respond + to a query with a Must, May, or No alias response, + indicating that two pointers always point to the same object, might point to the + same object, or are known to never point to the same object.

        + +

        The LLVM AliasAnalysis + class is the primary interface used by clients and implementations of alias + analyses in the LLVM system. This class is the common interface between clients + of alias analysis information and the implementations providing it, and is + designed to support a wide range of implementations and clients (but currently + all clients are assumed to be flow-insensitive). In addition to simple alias + analysis information, this class exposes Mod/Ref information from those + implementations which can provide it, allowing for powerful analyses and + transformations to work well together.

        + +

        This document contains information necessary to successfully implement this + interface, use it, and to test both sides. It also explains some of the finer + points about what exactly results mean. If you feel that something is unclear + or should be added, please let me + know.

        + +
        + + + + + +
        + +

        The AliasAnalysis + class defines the interface that the various alias analysis implementations + should support. This class exports two important enums: AliasResult + and ModRefResult which represent the result of an alias query or a + mod/ref query, respectively.

        + +

        The AliasAnalysis interface exposes information about memory, + represented in several different ways. In particular, memory objects are + represented as a starting address and size, and function calls are represented + as the actual call or invoke instructions that performs the + call. The AliasAnalysis interface also exposes some helper methods + which allow you to get mod/ref information for arbitrary instructions.

        + +
        + + + + +
        + +

        Most importantly, the AliasAnalysis class provides several methods + which are used to query whether or not two memory objects alias, whether + function calls can modify or read a memory object, etc. For all of these + queries, memory objects are represented as a pair of their starting address (a + symbolic LLVM Value*) and a static size.

        + +

        Representing memory objects as a starting address and a size is critically + important for correct Alias Analyses. For example, consider this (silly, but + possible) C code:

        + +
        +
        + int i;
        + char C[2];
        + char A[10]; 
        + /* ... */
        + for (i = 0; i != 10; ++i) {
        +   C[0] = A[i];          /* One byte store */
        +   C[1] = A[9-i];        /* One byte store */
        + }
        + 
        +
        + +

        In this case, the basicaa pass will disambiguate the stores to + C[0] and C[1] because they are accesses to two distinct + locations one byte apart, and the accesses are each one byte. In this case, the + LICM pass can use store motion to remove the stores from the loop. In + constrast, the following code:

        + +
        +
        + int i;
        + char C[2];
        + char A[10]; 
        + /* ... */
        + for (i = 0; i != 10; ++i) {
        +   ((short*)C)[0] = A[i];  /* Two byte store! */
        +   C[1] = A[9-i];          /* One byte store */
        + }
        + 
        +
        + +

        In this case, the two stores to C do alias each other, because the access to + the &C[0] element is a two byte access. If size information wasn't + available in the query, even the first case would have to conservatively assume + that the accesses alias.

        + +
        + + + + +
        + The alias method is the primary interface used to determine whether or + not two memory objects alias each other. It takes two memory objects as input + and returns MustAlias, MayAlias, or NoAlias as appropriate. +
        + + + + +
        + +

        An Alias Analysis implementation can return one of three responses: + MustAlias, MayAlias, and NoAlias. The No and May alias results are obvious: if + the two pointers can never equal each other, return NoAlias, if they might, + return MayAlias.

        + +

        The MustAlias response is trickier though. In LLVM, the Must Alias response + may only be returned if the two memory objects are guaranteed to always start at + exactly the same location. If two memory objects overlap, but do not start at + the same location, return MayAlias.

        + +
        + + + + +
        + +

        The getModRefInfo methods return information about whether the + execution of an instruction can read or modify a memory location. Mod/Ref + information is always conservative: if an instruction might read or write + a location, ModRef is returned.

        + +

        The AliasAnalysis class also provides a getModRefInfo + method for testing dependencies between function calls. This method takes two + call sites (CS1 & CS2), returns NoModRef if the two calls refer to disjoint + memory locations, Ref if CS1 reads memory written by CS2, Mod if CS1 writes to + memory read or written by CS2, or ModRef if CS1 might read or write memory + accessed by CS2. Note that this relation is not commutative. Clients that use + this method should be predicated on the hasNoModRefInfoForCalls() + method, which indicates whether or not an analysis can provide mod/ref + information for function call pairs (most can not). If this predicate is false, + the client shouldn't waste analysis time querying the getModRefInfo + method many times.

        + +
        + + + + + +
        + +

        + Several other tidbits of information are often collected by various alias + analysis implementations and can be put to good use by various clients. +

        + +
        + + +
        + The getMustAliases method +
        + +
        + +

        The getMustAliases method returns all values that are known to + always must alias a pointer. This information can be provided in some cases for + important objects like the null pointer and global values. Knowing that a + pointer always points to a particular function allows indirect calls to be + turned into direct calls, for example.

        + +
        + + +
        + The pointsToConstantMemory method +
        + +
        + +

        The pointsToConstantMemory method returns true if and only if the + analysis can prove that the pointer only points to unchanging memory locations + (functions, constant global variables, and the null pointer). This information + can be used to refine mod/ref information: it is impossible for an unchanging + memory location to be modified.

        + +
        + + + + + +
        + +

        These methods are used to provide very simple mod/ref information for + function calls. The doesNotAccessMemory method returns true for a + function if the analysis can prove that the function never reads or writes to + memory, or if the function only reads from constant memory. Functions with this + property are side-effect free and only depend on their input arguments, allowing + them to be eliminated if they form common subexpressions or be hoisted out of + loops. Many common functions behave this way (e.g., sin and + cos) but many others do not (e.g., acos, which modifies the + errno variable).

        + +

        The onlyReadsMemory method returns true for a function if analysis + can prove that (at most) the function only reads from non-volatile memory. + Functions with this property are side-effect free, only depending on their input + arguments and the state of memory when they are called. This property allows + calls to these functions to be eliminated and moved around, as long as there is + no store instruction that changes the contents of memory. Note that all + functions that satisfy the doesNotAccessMemory method also satisfies + onlyReadsMemory.

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

        Writing a new alias analysis implementation for LLVM is quite + straight-forward. There are already several implementations that you can use + for examples, and the following information should help fill in any details. + For a examples, take a look at the various alias analysis + implementations included with LLVM.

        + +
        + + + + +
        + +

        The first step to determining what type of LLVM pass you need to use for your Alias + Analysis. As is the case with most other analyses and transformations, the + answer should be fairly obvious from what type of problem you are trying to + solve:

        + +
          +
        1. If you require interprocedural analysis, it should be a + Pass.
        2. +
        3. If you are a function-local analysis, subclass FunctionPass.
        4. +
        5. If you don't need to look at the program at all, subclass + ImmutablePass.
        6. +
        + +

        In addition to the pass that you subclass, you should also inherit from the + AliasAnalysis interface, of course, and use the + RegisterAnalysisGroup template to register as an implementation of + AliasAnalysis.

        + +
        + + + + +
        + +

        Your subclass of AliasAnalysis is required to invoke two methods on + the AliasAnalysis base class: getAnalysisUsage and + InitializeAliasAnalysis. In particular, your implementation of + getAnalysisUsage should explicitly call into the + AliasAnalysis::getAnalysisUsage method in addition to doing any + declaring any pass dependencies your pass has. Thus you should have something + like this:

        + +
        +
        + void getAnalysisUsage(AnalysisUsage &AU) const {
        +   AliasAnalysis::getAnalysisUsage(AU);
        +   // declare your dependencies here.
        + }
        + 
        +
        + +

        Additionally, your must invoke the InitializeAliasAnalysis method + from your analysis run method (run for a Pass, + runOnFunction for a FunctionPass, or InitializePass + for an ImmutablePass). For example (as part of a Pass):

        + +
        +
        + bool run(Module &M) {
        +   InitializeAliasAnalysis(this);
        +   // Perform analysis here...
        +   return false;
        + }
        + 
        +
        + +
        + + + + +
        + +

        All of the AliasAnalysis + virtual methods default to providing chaining to another + alias analysis implementation, which ends up returning conservatively correct + information (returning "May" Alias and "Mod/Ref" for alias and mod/ref queries + respectively). Depending on the capabilities of the analysis you are + implementing, you just override the interfaces you can improve.

        + +
        + + + + + + +
        + +

        With only two special exceptions (the basicaa and no-aa + passes) every alias analysis pass chains to another alias analysis + implementation (for example, the user can specify "-basicaa -ds-aa + -anders-aa -licm" to get the maximum benefit from the three alias + analyses). The alias analysis class automatically takes care of most of this + for methods that you don't override. For methods that you do override, in code + paths that return a conservative MayAlias or Mod/Ref result, simply return + whatever the superclass computes. For example:

        + +
        +
        + AliasAnalysis::AliasResult alias(const Value *V1, unsigned V1Size,
        +                                  const Value *V2, unsigned V2Size) {
        +   if (...)
        +     return NoAlias;
        +   ...
        + 
        +   // Couldn't determine a must or no-alias result.
        +   return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
        + }
        + 
        +
        + +

        In addition to analysis queries, you must make sure to unconditionally pass + LLVM update notification methods to the superclass as + well if you override them, which allows all alias analyses in a change to be + updated.

        + +
        + + + + + +
        +

        + Alias analysis information is initially computed for a static snapshot of the + program, but clients will use this information to make transformations to the + code. All but the most trivial forms of alias analysis will need to have their + analysis results updated to reflect the changes made by these transformations. +

        + +

        + The AliasAnalysis interface exposes two methods which are used to + communicate program changes from the clients to the analysis implementations. + Various alias analysis implementations should use these methods to ensure that + their internal data structures are kept up-to-date as the program changes (for + example, when an instruction is deleted), and clients of alias analysis must be + sure to call these interfaces appropriately. +

        +
        + + +
        The deleteValue method
        + +
        + The deleteValue method is called by transformations when they remove an + instruction or any other value from the program (including values that do not + use pointers). Typically alias analyses keep data structures that have entries + for each value in the program. When this method is called, they should remove + any entries for the specified value, if they exist. +
        + + +
        The copyValue method
        + +
        + The copyValue method is used when a new value is introduced into the + program. There is no way to introduce a value into the program that did not + exist before (this doesn't make sense for a safe compiler transformation), so + this is the only way to introduce a new value. This method indicates that the + new value has exactly the same properties as the value being copied. +
        + + +
        The replaceWithNewValue method
        + +
        + This method is a simple helper method that is provided to make clients easier to + use. It is implemented by copying the old analysis information to the new + value, then deleting the old value. This method cannot be overridden by alias + analysis implementations. +
        + + + + +
        + +

        From the LLVM perspective, the only thing you need to do to provide an + efficient alias analysis is to make sure that alias analysis queries are + serviced quickly. The actual calculation of the alias analysis results (the + "run" method) is only performed once, but many (perhaps duplicate) queries may + be performed. Because of this, try to move as much computation to the run + method as possible (within reason).

        + +
        + + + + + +
        + +

        There are several different ways to use alias analysis results. In order of + preference, these are...

        + +
        + + + + +
        + +

        The load-vn pass uses alias analysis to provide value numbering + information for load instructions and pointer values. If your analysis + or transformation can be modeled in a form that uses value numbering + information, you don't have to do anything special to handle load instructions: + just use the load-vn pass, which uses alias analysis.

        + +
        + + + + +
        + +

        Many transformations need information about alias sets that are active + in some scope, rather than information about pairwise aliasing. The AliasSetTracker class + is used to efficiently build these Alias Sets from the pairwise alias analysis + information provided by the AliasAnalysis interface.

        + +

        First you initialize the AliasSetTracker by using the "add" methods + to add information about various potentially aliasing instructions in the scope + you are interested in. Once all of the alias sets are completed, your pass + should simply iterate through the constructed alias sets, using the + AliasSetTracker begin()/end() methods.

        + +

        The AliasSets formed by the AliasSetTracker are guaranteed + to be disjoint, calculate mod/ref information and volatility for the set, and + keep track of whether or not all of the pointers in the set are Must aliases. + The AliasSetTracker also makes sure that sets are properly folded due to call + instructions, and can provide a list of pointers in each set.

        + +

        As an example user of this, the Loop + Invariant Code Motion pass uses AliasSetTrackers to calculate alias + sets for each loop nest. If an AliasSet in a loop is not modified, + then all load instructions from that set may be hoisted out of the loop. If any + alias sets are stored to and are must alias sets, then the stores may be + sunk to outside of the loop, promoting the memory location to a register for the + duration of the loop nest. Both of these transformations only apply if the + pointer argument is loop-invariant.

        + +
        + + +
        + The AliasSetTracker implementation +
        + +
        + +

        The AliasSetTracker class is implemented to be as efficient as possible. It + uses the union-find algorithm to efficiently merge AliasSets when a pointer is + inserted into the AliasSetTracker that aliases multiple sets. The primary data + structure is a hash table mapping pointers to the AliasSet they are in.

        + +

        The AliasSetTracker class must maintain a list of all of the LLVM Value*'s + that are in each AliasSet. Since the hash table already has entries for each + LLVM Value* of interest, the AliasesSets thread the linked list through these + hash-table nodes to avoid having to allocate memory unnecessarily, and to make + merging alias sets extremely efficient (the linked list merge is constant time). +

        + +

        You shouldn't need to understand these details if you are just a client of + the AliasSetTracker, but if you look at the code, hopefully this brief + description will help make sense of why things are designed the way they + are.

        + +
        + + + + +
        + +

        If neither of these utility class are what your pass needs, you should use + the interfaces exposed by the AliasAnalysis class directly. Try to use + the higher-level methods when possible (e.g., use mod/ref information instead of + the alias method directly if possible) to get the + best precision and efficiency.

        + +
        + + + + + +
        + +

        If you're going to be working with the LLVM alias analysis infrastructure, + you should know what clients and implementations of alias analysis are + available. In particular, if you are implementing an alias analysis, you should + be aware of the the clients that are useful + for monitoring and evaluating different implementations.

        + +
        + + + + +
        + +

        This section lists the various implementations of the AliasAnalysis + interface. With the exception of the -no-aa and + -basicaa implementations, all of these chain to other alias analysis implementations.

        + +
        + + + + +
        + +

        The -no-aa pass is just like what it sounds: an alias analysis that + never returns any useful information. This pass can be useful if you think that + alias analysis is doing something wrong and are trying to narrow down a + problem.

        + +
        + + + + +
        + +

        The -basicaa pass is the default LLVM alias analysis. It is an + aggressive local analysis that "knows" many important facts:

        + +
          +
        • Distinct globals, stack allocations, and heap allocations can never + alias.
        • +
        • Globals, stack allocations, and heap allocations never alias the null + pointer.
        • +
        • Different fields of a structure do not alias.
        • +
        • Indexes into arrays with statically differing subscripts cannot alias.
        • +
        • Many common standard C library functions never access memory or only read memory.
        • +
        • Pointers that obviously point to constant globals + "pointToConstantMemory".
        • +
        • Function calls can not modify or references stack allocations if they never + escape from the function that allocates them (a common case for automatic + arrays).
        • +
        + +
        + + + + +
        + +

        This pass implements a simple context-sensitive mod/ref and alias analysis + for internal global variables that don't "have their address taken". If a + global does not have its address taken, the pass knows that no pointers alias + the global. This pass also keeps track of functions that it knows never access + memory or never read memory. This allows certain optimizations (e.g. GCSE) to + eliminate call instructions entirely. +

        + +

        The real power of this pass is that it provides context-sensitive mod/ref + information for call instructions. This allows the optimizer to know that + calls to a function do not clobber or read the value of the global, allowing + loads and stores to be eliminated.

        + +

        Note that this pass is somewhat limited in its scope (only support + non-address taken globals), but is very quick analysis.

        +
        + + + + +
        + +

        The -anders-aa pass implements the well-known "Andersen's algorithm" + for interprocedural alias analysis. This algorithm is a subset-based, + flow-insensitive, context-insensitive, and field-insensitive alias analysis that + is widely believed to be fairly precise. Unfortunately, this algorithm is also + O(N3). The LLVM implementation currently does not implement any of + the refinements (such as "online cycle elimination" or "offline variable + substitution") to improve its efficiency, so it can be quite slow in common + cases. +

        + +
        + + + + +
        + +

        The -steens-aa pass implements a variation on the well-known + "Steensgaard's algorithm" for interprocedural alias analysis. Steensgaard's + algorithm is a unification-based, flow-insensitive, context-insensitive, and + field-insensitive alias analysis that is also very scalable (effectively linear + time).

        + +

        The LLVM -steens-aa pass implements a "speculatively + field-sensitive" version of Steensgaard's algorithm using the Data + Structure Analysis framework. This gives it substantially more precision than + the standard algorithm while maintaining excellent analysis scalability.

        + +
        + + + + +
        + +

        The -ds-aa pass implements the full Data Structure Analysis + algorithm. Data Structure Analysis is a modular unification-based, + flow-insensitive, context-sensitive, and speculatively + field-sensitive alias analysis that is also quite scalable, usually at + O(n*log(n)).

        + +

        This algorithm is capable of responding to a full variety of alias analysis + queries, and can provide context-sensitive mod/ref information as well. The + only major facility not implemented so far is support for must-alias + information.

        + +
        + + + + + +
        + LLVM includes several alias-analysis driven transformations which can be used + with any of the implementations above. +
        + + + + +
        + +

        The -adce pass, which implements Aggressive Dead Code Elimination + uses the AliasAnalysis interface to delete calls to functions that do + not have side-effects and are not used.

        + +
        + + + + + +
        + +

        The -licm pass implements various Loop Invariant Code Motion related + transformations. It uses the AliasAnalysis interface for several + different transformations:

        + +
          +
        • It uses mod/ref information to hoist or sink load instructions out of loops + if there are no instructions in the loop that modifies the memory loaded.
        • + +
        • It uses mod/ref information to hoist function calls out of loops that do not + write to memory and are loop-invariant.
        • + +
        • If uses alias information to promote memory objects that are loaded and + stored to in loops to live in a register instead. It can do this if there are + no may aliases to the loaded/stored memory location.
        • +
        + +
        + + + + +
        +

        + The -argpromotion pass promotes by-reference arguments to be passed in + by-value instead. In particular, if pointer arguments are only loaded from it + passes in the value loaded instead of the address to the function. This pass + uses alias information to make sure that the value loaded from the argument + pointer is not modified between the entry of the function and any load of the + pointer.

        +
        + + + + +
        + +

        The -load-vn pass uses alias analysis to "value + number" loads and pointers values, which is used by the GCSE pass to + eliminate instructions. The -load-vn pass relies on alias information + and must-alias information. This combination of passes can make the following + transformations:

        + +
          +
        • Redundant load instructions are eliminated.
        • +
        • Load instructions that follow a store to the same location are replaced with + the stored value ("store forwarding").
        • +
        • Pointers values (e.g. formal arguments) that must-alias simpler expressions + (e.g. global variables or the null pointer) are replaced. Note that this + implements transformations like "virtual method resolution", turning indirect + calls into direct calls.
        • +
        + +
        + + + + +
        + +

        These passes are useful for evaluating the various alias analysis + implementations. You can use them with commands like 'opt -anders-aa -ds-aa + -aa-eval foo.bc -disable-output -stats'.

        + +
        + + + + +
        + +

        The -print-alias-sets pass is exposed as part of the + analyze tool to print out the Alias Sets formed by the AliasSetTracker class. This is useful if you're using + the AliasSetTracker class.

        + +
        + + + + + +
        + +

        The -count-aa pass is useful to see how many queries a particular + pass is making and what responses are returned by the alias analysis. As an + example,

        + +
        +
        + % opt -basicaa -count-aa -ds-aa -count-aa -licm
        + 
        +
        + +

        will print out how many queries (and what responses are returned) by the + -licm pass (of the -ds-aa pass) and how many queries are made + of the -basicaa pass by the -ds-aa pass. This can be useful + when debugging a transformation or an alias analysis implementation.

        + +
        + + + + +
        + +

        The -aa-eval pass simply iterates through all pairs of pointers in a + function and asks an alias analysis whether or not the pointers alias. This + gives an indication of the precision of the alias analysis. Statistics are + printed indicating the percent of no/may/must aliases found (a more precise + algorithm will have a lower number of may aliases).

        + +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
        + LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + + + Index: llvm-www/releases/1.3/docs/Bugpoint.html diff -c /dev/null llvm-www/releases/1.3/docs/Bugpoint.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/Bugpoint.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,245 ---- + + LLVM: bugpoint tool + + + +

        LLVM: bugpoint tool

        +
        + +

        NAME

        + bugpoint + +

        SYNOPSIS

        + bugpoint [options] [input LLVM ll/bc files] [LLVM passes] --args <program arguments>... + + +

        DESCRIPTION

        + + The bugpoint tool narrows down the source of + problems in LLVM tools and passes. It can be used to debug three types of + failures: optimizer crashes, miscompilations by optimizers, or bad native + code generation (including problems in the static and JIT compilers). It aims + to reduce large test cases to small, useful ones. For example, + if gccas crashes while optimizing a file, it + will identify the optimization (or combination of optimizations) that causes the + crash, and reduce the file down to a small example which triggers the crash.

        + + +

        Design Philosophy

        + + bugpoint is designed to be a useful tool without requiring any + hooks into the LLVM infrastructure at all. It works with any and all LLVM + passes and code generators, and does not need to "know" how they work. Because + of this, it may appear to do stupid things or miss obvious + simplifications. bugpoint is also designed to trade off programmer + time for computer time in the compiler-debugging process; consequently, it may + take a long period of (unattended) time to reduce a test case, but we feel it + is still worth it. Note that bugpoint is generally very quick unless + debugging a miscompilation where each test of the program (which requires + executing it) takes a long time.

        + + +

        Automatic Debugger Selection

        + + bugpoint reads each .bc or .ll file + specified on the command line and links them together into a single module, + called the test program. If any LLVM passes are + specified on the command line, it runs these passes on the test program. If + any of the passes crash, or if they produce malformed output (which causes the + verifier to abort), + 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 + bugpoint has a reference output for the test program, it tries + 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 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 38 passes.

        + + 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 + 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, analyze, or llc.

        + + +

        Code generator debugger

        + +

        The code generator debugger attempts to narrow down the amount of code that + is being miscompiled by the selected code generator. To + do this, it takes the test program and partitions it into two pieces: one piece + which it compiles with the C backend (into a shared object), and one piece which + it runs with either the JIT or the static LLC compiler. It uses several + techniques to reduce the amount of code pushed through the LLVM code generator, + to reduce the potential scope of the problem. After it is finished, it emits + two bytecode files (called "test" [to be compiled with the code generator] and + "safe" [to be compiled with the C backend], respectively), and instructions for + reproducing the problem. The code generator debugger assumes that the C backend + produces good code.

        + + +

        Miscompilation debugger

        + + The miscompilation debugger works similarly to the code generator + debugger. It works by splitting the test program into two pieces, running the + optimizations specified on one piece, linking the two pieces back together, + and then executing the result. + It attempts to narrow down the list of passes to the one (or few) which are + causing the miscompilation, then reduce the portion of the test program which is + being miscompiled. The miscompilation debugger assumes that the selected + code generator is working properly.

        + + +

        Advice for using bugpoint

        + + bugpoint can be a remarkably useful tool, but it sometimes works in + non-obvious ways. Here are some hints and tips:

        + +

          +
        1. In the code generator and miscompilation debuggers, bugpoint only + works with programs that have deterministic output. Thus, if the program + outputs argv[0], the date, time, or any other "random" data, bugpoint may + misinterpret differences in these data, when output, as the result of a + miscompilation. Programs should be temporarily modified to disable + outputs that are likely to vary from run to run. + +
        2. In the code generator and miscompilation debuggers, debugging will go + faster if you manually modify the program or its inputs to reduce the + runtime, but still exhibit the problem. + +
        3. bugpoint is extremely useful when working on a new optimization: + it helps track down regressions quickly. To avoid having to relink + bugpoint every time you change your optimization however, have + bugpoint dynamically load your optimization with the -load option. + +
        4. bugpoint can generate a lot of output and run for a long period of + time. It is often useful to capture the output of the program to file. For + example, in the C shell, you can type:
          + bugpoint ..... |& tee bugpoint.log +
          to get a copy of bugpoint's output in the file + bugpoint.log, as well as on your terminal. + +
        5. bugpoint cannot debug problems with the LLVM linker. If + 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. + +
        6. 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

        + + + +

        EXIT STATUS

        + + If bugpoint succeeds in finding a problem, it will exit with 0. + Otherwise, if an error occurs, it will exit with a non-zero value. + +
        + Maintained by the
        LLVM Team. + + Index: llvm-www/releases/1.3/docs/BytecodeFormat.html diff -c /dev/null llvm-www/releases/1.3/docs/BytecodeFormat.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/BytecodeFormat.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,1638 ---- + + + + LLVM Bytecode File Format + + + + +
        LLVM Bytecode File Format
        +
          +
        1. Abstract
        2. +
        3. Concepts +
            +
          1. Blocks
          2. +
          3. Lists
          4. +
          5. Fields
          6. +
          7. Alignment
          8. +
          9. Variable Bit-Rate Encoding
          10. +
          11. Encoding Primitives
          12. +
          13. Slots
          14. +
          +
        4. +
        5. General Structure
        6. +
        7. Block Definitions +
            +
          1. Signature Block
          2. +
          3. Module Block
          4. +
          5. Global Type Pool
          6. +
          7. Module Info Block
          8. +
          9. Global Constant Pool
          10. +
          11. Function Definition
          12. +
          13. Compaction Table
          14. +
          15. Instruction List
          16. +
          17. Symbol Table
          18. +
          +
        8. +
        9. Version Differences +
            +
          1. Version 1.2 Differences From 1.3
          2. +
          3. Version 1.1 Differences From 1.2
          4. +
          5. Version 1.0 Differences From 1.1
          6. +
          +
        10. +
        +
        +

        Written by Reid Spencer +

        +
        + + + +
        +

        This document describes the LLVM bytecode file format. It specifies + the binary encoding rules of the bytecode file format so that + equivalent systems can encode bytecode files correctly. The LLVM + bytecode representation is used to store the intermediate + representation on disk in compacted form.

        +

        The LLVM bytecode format may change in the future, but LLVM will + always be backwards compatible with older formats. This document will + only describe the most current version of the bytecode format. See Version Differences for the details on how + the current version is different from previous versions.

        +
        + + + +
        +

        This section describes the general concepts of the bytecode file + format without getting into specific layout details. It is recommended + that you read this section thoroughly before interpreting the detailed + descriptions.

        +
        + + +
        +

        LLVM bytecode files consist simply of a sequence of blocks of bytes + using a binary encoding Each block begins with an header of two + unsigned integers. The first value identifies the type of block and the + second value provides the size of the block in bytes. The block + identifier is used because it is possible for entire blocks to be + omitted from the file if they are empty. The block identifier helps the + reader determine which kind of block is next in the file. Note that + blocks can be nested within other blocks.

        +

        All blocks are variable length, and the block header specifies the + size of the block. All blocks begin on a byte index that is aligned to + an even 32-bit boundary. That is, the first block is 32-bit aligned + because it starts at offset 0. Each block is padded with zero fill + bytes to ensure that the next block also starts on a 32-bit boundary.

        +
        + + +
        +

        LLVM Bytecode blocks often contain lists of things of a similar + type. For example, a function contains a list of instructions and a + function type contains a list of argument types. There are two basic + types of lists: length lists (llist), and null + terminated lists (zlist), as described below in + the Encoding Primitives.

        +
        + + +
        +

        Fields are units of information that LLVM knows how to write atomically. Most + fields have a uniform length or some kind of length indication built into their + encoding. For example, a constant string (array of bytes) is written simply as + the length followed by the characters. Although this is similar to a list, + constant strings are treated atomically and are thus fields.

        +

        Fields use a condensed bit format specific to the type of information + they must contain. As few bits as possible are written for each field. The + sections that follow will provide the details on how these fields are + written and how the bits are to be interpreted.

        +
        + + +
        +

        To support cross-platform differences, the bytecode file is aligned on + certain boundaries. This means that a small amount of padding (at most 3 + bytes) will be added to ensure that the next entry is aligned to a 32-bit + boundary.

        +
        + + +
        +

        Most of the values written to LLVM bytecode files are small integers. To + minimize the number of bytes written for these quantities, an encoding scheme + similar to UTF-8 is used to write integer data. The scheme is known as + variable bit rate (vbr) encoding. In this encoding, the high bit of + each byte is used to indicate if more bytes follow. If (byte & + 0x80) is non-zero in any given byte, it means there is another byte + immediately following that also contributes to the value. For the final + byte (byte & 0x80) is false (the high bit is not set). In each byte + only the low seven bits contribute to the value. Consequently 32-bit + quantities can take from one to five bytes to encode. In + general, smaller quantities will encode in fewer bytes, as follows:

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Byte #Significant BitsMaximum Value
        10-6127
        27-1316,383
        314-202,097,151
        421-27268,435,455
        528-3434,359,738,367
        635-414,398,046,511,103
        742-48562,949,953,421,311
        849-5572,057,594,037,927,935
        956-629,223,372,036,854,775,807
        1063-691,180,591,620,717,411,303,423
        +

        Note that in practice, the tenth byte could only encode bit 63 since + the maximum quantity to use this encoding is a 64-bit integer.

        +

        Signed VBR values are encoded with the standard vbr + encoding, but with the sign bit as the low order bit instead of the + high order bit. This allows small negative quantities to be encoded + efficiently. For example, -3 + is encoded as "((3 << 1) | 1)" and 3 is encoded as "(3 << + 1) | 0)", emitted with the standard vbr encoding above.

        +
        + + +
        +

        Each field in the bytecode format is encoded into the file using a + small set of primitive formats. The table below defines the encoding + rules for the various primitives used and gives them each a type name. + The type names used in the descriptions of blocks and fields in the Detailed Layoutnext section. Any type name with + the suffix _vbr indicates a quantity that is encoded using + variable bit rate encoding as described above.

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeRule
        unsignedA 32-bit unsigned integer that always occupies four + consecutive bytes. The unsigned integer is encoded using LSB first + ordering. That is bits 20 through 27 are in the + byte with the lowest file offset (little endian).
        + uint24_vbrA 24-bit unsigned + integer that occupies from one to four bytes using variable bit rate + encoding.
        uint32_vbrA 32-bit unsigned integer that occupies from one to + five bytes using variable bit rate encoding.
        uint64_vbrA 64-bit unsigned integer that occupies from one to ten + bytes using variable bit rate encoding.
        int64_vbrA 64-bit signed integer that occupies from one to ten + bytes using the signed variable bit rate encoding.
        charA single unsigned character encoded into one byte
        bit(n-m)A set of bit within some larger integer field. The values + of n and m specify the inclusive range of bits + that define the subfield. The value for m may be omitted if + its the same as n.
        floatA floating point value encoded + as a 32-bit IEEE value written in little-endian form.
        +
        doubleA floating point value encoded + as a64-bit IEEE value written in little-endian form
        stringA uint32_vbr indicating the type of the + constant string which also includes its length, immediately followed by + the characters of the string. There is no terminating null byte in the + string.
        dataAn arbitrarily long segment of data to which + no interpretation is implied. This is used for constant initializers.
        +
        llist(x)A length list of x. This means the list is + encoded as an uint32_vbr providing the + length of the list, followed by a sequence of that many "x" items. This + implies that the reader should iterate the number of times provided by + the length.
        zlist(x)A zero-terminated list of x. This means the + list is encoded as a sequence of an indeterminate number of "x" items, + followed by an uint32_vbr terminating value. + This implies that none of the "x" items can have a zero value (or else + the list terminates).
        blockA block of data that is logically related. A + block is an unsigned 32-bit integer that encodes the type of the block + in the low 5 bits and the size of the block in the high 27 bits. The + length does not include the block header or any alignment bytes at the + end of the block. Blocks may compose other blocks.
        +
        + + +
        +

        In the detailed block and field descriptions that follow, a regex + like notation is used to describe optional and repeated fields. A very + limited subset of regex is used to describe these, as given in the + following table:

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        CharacterMeaning
        ?The question mark indicates 0 or 1 + occurrences of the thing preceding it.
        *The asterisk indicates 0 or more occurrences + of the thing preceding it.
        +The plus sign indicates 1 or more occurrences + of the thing preceding it.
        ()Parentheses are used for grouping.
        ,The comma separates sequential fields.
        +

        So, for example, consider the following specifications:

        +
        +
          +
        1. string?
        2. +
        3. (uint32_vbr,uin32_vbr)+
        4. +
        5. (unsigned?,uint32_vbr)*
        6. +
        7. (llist(unsigned))?
        8. +
        +
        +

        with the following interpretations:

        +
          +
        1. An optional string. Matches either nothing or a single string
        2. +
        3. One or more pairs of uint32_vbr.
        4. +
        5. Zero or more occurrences of either an unsigned followed by a + uint32_vbr or just a uint32_vbr.
        6. +
        7. An optional length list of unsigned values.
        8. +
        +
        + + +
        +

        The bytecode format uses the notion of a "slot" to reference Types + and Values. Since the bytecode file is a direct representation of + LLVM's intermediate representation, there is a need to represent pointers in + the file. Slots are used for this purpose. For example, if one has the following + assembly: +

        +
        %MyType = type { int, sbyte }
        + %MyVar = external global %MyType +
        +

        there are two definitions. The definition of %MyVar uses %MyType. + In the C++ IR this linkage between %MyVar and %MyType + is explicit through the use of C++ pointers. In bytecode, however, there's no + ability to store memory addresses. Instead, we compute and write out + slot numbers for every Type and Value written to the file.

        +

        A slot number is simply an unsigned 32-bit integer encoded in the variable + bit rate scheme (see encoding). This ensures that + low slot numbers are encoded in one byte. Through various bits of magic LLVM + attempts to always keep the slot numbers low. The first attempt is to associate + slot numbers with their "type plane". That is, Values of the same type + are written to the bytecode file in a list (sequentially). Their order in + that list determines their slot number. This means that slot #1 doesn't mean + anything unless you also specify for which type you want slot #1. Types are + handled specially and are always written to the file first (in the Global Type Pool) and in such a way that both forward + and backward references of the types can often be resolved with a single pass + through the type pool.

        +

        Slot numbers are also kept small by rearranging their order. Because + of the structure of LLVM, certain values are much more likely to be used + frequently in the body of a function. For this reason, a compaction table is + provided in the body of a function if its use would make the function body + smaller. Suppose you have a function body that uses just the types "int*" and + "{double}" but uses them thousands of time. Its worthwhile to ensure that the + slot number for these types are low so they can be encoded in a single byte + (via vbr). This is exactly what the compaction table does.

        +
        + + + +
        +

        This section provides the general structure of the LLVM bytecode + file format. The bytecode file format requires blocks to be in a + certain order and nested in a particular way so that an LLVM module can + be constructed efficiently from the contents of the file. This ordering + defines a general structure for bytecode files as shown below. The + table below shows the order in which all block types may appear. Please + note that some of the blocks are optional and some may be repeated. The + structure is fairly loose because optional blocks, if empty, are + completely omitted from the file.

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        IDParentOptional?Repeated?LevelBlock TypeDescription
        N/AFileNoNo0SignatureThis contains the file signature (magic + number) that identifies the file as LLVM bytecode.
        0x01FileNoNo0ModuleThis is the top level block in a bytecode + file. It contains all the other blocks.
        0x06ModuleNoNo1   Global Type PoolThis block contains all the global (module) + level types.
        0x05ModuleNoNo1   Module Globals InfoThis block contains the type, constness, and + linkage for each of the global variables in the module. It also + contains the type of the functions and the constant initializers.
        0x03ModuleYesNo1   Module Constant PoolThis block contains all the global constants + except function arguments, global values and constant strings.
        0x02ModuleYesYes1   Function Definitions*One function block is written for each + function in the module. The function block contains the instructions, + compaction table, type constant pool, and symbol table for the function.
        0x03FunctionYesNo2      Function Constant PoolAny constants (including types) used solely + within the function are emitted here in the function constant pool.
        0x08FunctionYesNo2      Compaction TableThis table reduces bytecode size by providing + a funtion-local mapping of type and value slot numbers to their global + slot numbers
        0x07FunctionNoNo2      Instruction ListThis block contains all the instructions of + the function. The basic blocks are inferred by terminating + instructions.
        0x04FunctionYesNo2      Function Symbol TableThis symbol table provides the names for the + function specific values used (basic block labels mostly).
        0x04ModuleYesNo1   Module Symbol TableThis symbol table provides the names for the + various entries in the file that are not function specific (global + vars, and functions mostly).
        +

        Use the links in the table for details about the contents of each of + the block types.

        +
        + + + +
        +

        This section provides the detailed layout of the individual block + types in the LLVM bytecode file format.

        +
        + + +
        +

        The signature occurs in every LLVM bytecode file and is always first. + It simply provides a few bytes of data to identify the file as being an LLVM + bytecode file. This block is always four bytes in length and differs from the + other blocks because there is no identifier and no block length at the start + of the block. Essentially, this block is just the "magic number" for the file. +

        + + + + + + + + + + + + + + + + + + + + + + + +
        TypeField Description
        charConstant "l" (0x6C)
        charConstant "l" (0x6C)
        charConstant "v" (0x76)
        charConstant "m" (0x6D)
        +
        + + +
        +

        The module block contains a small pre-amble and all the other blocks in + the file. The table below shows the structure of the module block. Note that it + only provides the module identifier, size of the module block, and the format + information. Everything else is contained in other blocks, described in other + sections.

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeField Description
        block
        +
        Module Block Identifier (0x01) and Size
        +
        uint32_vbrFormat Information
        blockGlobal Type Pool
        blockModule Globals Info
        blockModule Constant Pool
        block*Function Definitions
        blockModule Symbol Table
        +
        + + +
        +

        The format information field is encoded into a uint32_vbr + as shown in the following table.

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeDescription
        bit(0)Target is big endian?
        bit(1)On target pointers are 64-bit?
        bit(2)Target has no endianess?
        bit(3)Target has no pointer size?
        bit(4-31)Bytecode format version
        +

        + Of particular note, the bytecode format number is simply a 28-bit + monotonically increase integer that identifies the version of the bytecode + format (which is not directly related to the LLVM release number). The + bytecode versions defined so far are (note that this document only + describes the latest version, 1.3):

        +
          +
        • #0: LLVM 1.0 & 1.1
        • +
        • #1: LLVM 1.2
        • +
        • #2: LLVM 1.2.5 (not released)
        • +
        • #3: LLVM 1.3
          +
        • +
        +

        Note that we plan to eventually expand the target description + capabilities + of bytecode files to target + triples. +

        +
        + + +
        +

        The global type pool consists of type definitions. Their order of appearance + in the file determines their slot number (0 based). Slot numbers are + used to replace pointers in the intermediate representation. Each slot number + uniquely identifies one entry in a type plane (a collection of values of the + same type). Since all values have types and are associated with the order in + which the type pool is written, the global type pool must be written + as the first block of a module. If it is not, attempts to read the file will + fail because both forward and backward type resolution will not be possible.

        +

        The type pool is simply a list of type definitions, as shown in the + table below.

        + + + + + + + + + + + + + + + +
        TypeField Description
        blockType Pool Identifier (0x06) + Size
        +
        llist(type)A length list of type definitions.
        +
        + + +
        +

        Types in the type pool are defined using a different format for each kind + of type, as given in the following sections.

        +

        Primitive Types

        +

        The primitive types encompass the basic integer and floating point + types

        + + + + + + + + + + + +
        TypeDescription
        uint24_vbrType ID for the primitive types (values 1 to + 11) 1
        + Notes: +
          +
        1. The values for the Type IDs for the primitive types are provided + by the definition of the llvm::Type::TypeID enumeration + in include/llvm/Type.h. The enumeration gives the + following mapping: +
            +
          1. bool
          2. +
          3. ubyte
          4. +
          5. sbyte
          6. +
          7. ushort
          8. +
          9. short
          10. +
          11. uint
          12. +
          13. int
          14. +
          15. ulong
          16. +
          17. long
          18. +
          19. float
          20. +
          21. double
          22. +
          +
        2. +
        +

        Function Types

        + + + + + + + + + + + + + + + + + + + + + + + +
        TypeDescription
        uint24_vbrType ID for function types (13)
        uint24_vbrSlot number of function's return type.
        llist(uint24_vbr)Slot number of each argument's type.
        uint32_vbr?Value 0 if this is a varargs function, + missing otherwise.
        +

        Structure Types

        + + + + + + + + + + + + + + + +
        TypeDescription
        uint24_vbrType ID for structure types (14)
        zlist(uint24_vbr)Slot number of each of the element's fields.
        +

        Array Types

        + + + + + + + + + + + + + + + + + + + +
        TypeDescription
        uint24_vbrType ID for Array Types (15)
        uint24_vbrSlot number of array's element type.
        uint32_vbrThe number of elements in the array.
        +

        Pointer Types

        + + + + + + + + + + + + + + + +
        TypeDescription
        uint24_vbrType ID For Pointer Types (16)
        uint24_vbrSlot number of pointer's element type.
        +

        Opaque Types

        + + + + + + + + + + + +
        TypeDescription
        uint24_vbrType ID For Opaque Types (17)
        +
        + + +
        +

        The module global info block contains the definitions of all global + variables including their initializers and the declaration of + all functions. The format is shown in the table below:

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeField Description
        blockModule global info identifier (0x05) + size
        +
        zlist(globalvar)A zero terminated list of global var + definitions occuring in the module.
        zlist(uint24_vbr)A zero terminated list of function types + occuring in the module.
        llist(string)
        +
        A length list + of strings that specify the names of the libraries that this module + depends upon.
        +
        string
        +
        The target + triple for the module (blank means no target triple specified, i.e. a + platform independent module).
        +
        +
        + + +
        +

        Global variables are written using an uint32_vbr + that encodes information about the global variable and a list of the + constant initializers for the global var, if any.

        +

        The table below provides the bit layout of the first uint32_vbr that describes the global variable.

        + + + + + + + + + + + + + + + + + + + + + + + +
        TypeDescription
        bit(0)Is constant?
        bit(1)Has initializer? Note that this bit + determines whether the constant initializer field (described below) + follows.
        bit(2-4)Linkage type: 0=External, 1=Weak, + 2=Appending, 3=Internal, 4=LinkOnce
        bit(5-31)Slot number of type for the global variable.
        +

        The table below provides the format of the constant initializers for + the global variable field, if it has one.

        + + + + + + + + + + + +
        TypeDescription
        (zlist(uint32_vbr))? + An optional zero-terminated list of slot + numbers of the global variable's constant initializer.
        +
        + + +
        +

        A constant pool defines as set of constant values. There are + actually two types of constant pool blocks: one for modules and one for + functions. For modules, the block begins with the constant strings + encountered anywhere in the module. For functions, the block begins + with types only encountered in the function. In both cases the header + is identical. The tables that follow, show the header, module constant + pool preamble, function constant pool preamble, and the part common to + both function and module constant pools.

        +

        Common Block Header

        + + + + + + + + + + + +
        TypeField Description
        blockConstant pool identifier (0x03) + size
        +
        +

        Module Constant Pool Preamble (constant strings)

        + + + + + + + + + + + + + + + + + + + +
        TypeField Description
        uint32_vbrThe number of constant strings that follow.
        uint32_vbrZero. This identifies the following "plane" + as containing the constant strings. This is needed to identify it + uniquely from other constant planes that follow.
        uint24_vbr+Slot number of the constant string's type. + Note that the constant string's type implicitly defines the length of + the string.
        +

        Function Constant Pool Preamble (function types)

        +

        The structure of the types for functions is identical to the Global Type Pool. Please refer to that section + for the details.

        +

        Common Part (other constants)

        + + + + + + + + + + + + + + + + + + + +
        TypeField Description
        uint32_vbrNumber of entries in this type plane.
        uint24_vbrType slot number of this plane.
        constant+The definition of a constant (see below).
        +
        + + +
        +

        Constants come in many shapes and flavors. The sections that followe + define the format for each of them. All constants start with a uint32_vbr encoded integer that provides the + number of operands for the constant. For primitive, structure, and + array constants, this will always be zero since those types of + constants have no operands. In this case, we have the following field + definitions:

        +
          +
        • Bool. This is written as an uint32_vbr + of value 1U or 0U.
        • +
        • Signed Integers (sbyte,short,int,long). These are written + as an int64_vbr with the corresponding value.
        • +
        • Unsigned Integers (ubyte,ushort,uint,ulong). These are + written as an uint64_vbr with the + corresponding value.
        • +
        • Floating Point. Both the float and double types are + written literally in binary format.
        • +
        • Arrays. Arrays are written simply as a list of uint32_vbr encoded slot numbers to the constant + element values.
        • +
        • Structures. Structures are written simply as a list of uint32_vbr encoded slot numbers to the constant + field values of the structure.
        • +
        +

        When the number of operands to the constant is non-zero, we have a + constant expression and its field format is provided in the table below.

        + + + + + + + + + + + + + + + + + + + +
        TypeField Description
        uint32_vbrOp code of the instruction for the constant + expression.
        uint32_vbrThe slot number of the constant value for an + operand.1
        uint24_vbrThe slot number for the type of the constant + value for an operand.1
        + Notes: +
          +
        1. Both these fields are repeatable but only in pairs.
        2. +
        +
        + + +
        +

        Function definitions contain the linkage, constant pool or + compaction table, instruction list, and symbol table for a function. + The following table shows the structure of a function definition.

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeField Description
        block
        +
        Function definition block identifier (0x02) + + size
        +
        uint32_vbrThe linkage type of the function: 0=External, + 1=Weak, 2=Appending, 3=Internal, 4=LinkOnce1
        blockThe constant pool + block for this function.2
        blockThe compaction + table block for the function.2
        blockThe instruction + list for the function.
        blockThe function's symbol + table containing only those symbols pertinent to the function + (mostly block labels).
        + Notes: +
          +
        1. Note that if the linkage type is "External" then none of the + other fields will be present as the function is defined elsewhere.
        2. +
        3. Note that only one of the constant pool or compaction table will + be written. Compaction tables are only written if they will actually + save bytecode space. If not, then a regular constant pool is written.
        4. +
        +
        + + +
        +

        Compaction tables are part of a function definition. They are merely + a device for reducing the size of bytecode files. The size of a + bytecode file is dependent on the value of the slot numbers + used because larger values use more bytes in the variable bit rate + encoding scheme. Furthermore, the compressed instruction format + reserves only six bits for the type of the instruction. In large + modules, declaring hundreds or thousands of types, the values of the + slot numbers can be quite large. However, functions may use only a + small fraction of the global types. In such cases a compaction table is + created that maps the global type and value slot numbers to smaller + values used by a function. Functions will contain either a + function-specific constant pool or a compaction table but not + both. Compaction tables have the format shown in the table below.

        + + + + + + + + + + + + + + + + + + + + + + + +
        TypeField Description
        uint32_vbrThe number of types that follow
        uint24_vbr+The slot number in the global type plane of + the type that will be referenced in the function with the index of this + entry in the compaction table.
        type_lenAn encoding of the type and number of values + that follow. This field's encoding varies depending on the size of the + type plane. See Type and Length for further + details.
        uint32_vbr+The slot number in the globals of the value + that will be referenced in the function with the index of this entry in + the compaction table
        +
        + + +
        +

        The type and length of a compaction table type plane is encoded + differently depending on the length of the plane. For planes of length + 1 or 2, the length is encoded into bits 0 and 1 of a uint32_vbr and the type is encoded into bits + 2-31. Because type numbers are often small, this often saves an extra + byte per plane. If the length of the plane is greater than 2 then the + encoding uses a uint32_vbr for each of the + length and type, in that order.

        +
        + + +
        +

        The instructions in a function are written as a simple list. Basic + blocks are inferred by the terminating instruction types. The format of + the block is given in the following table.

        + + + + + + + + + + + + + + + +
        TypeField Description
        block
        +
        Instruction list identifier (0x07) + size
        +
        instruction+An instruction. Instructions have a variety + of formats. See Instructions for details.
        +
        + + +
        +

        For brevity, instructions are written in one of four formats, + depending on the number of operands to the instruction. Each + instruction begins with a uint32_vbr that + encodes the type of the instruction as well as other things. The tables + that follow describe the format of this first word of each instruction.

        +

        Instruction Format 0

        +

        This format is used for a few instructions that can't easily be + optimized because they have large numbers of operands (e.g. PHI Node or + getelementptr). Each of the opcode, type, and operand fields is as + successive fields.

        + + + + + + + + + + + + + + + + + + + + + + + +
        TypeField Description
        uint32_vbrSpecifies the opcode of the instruction. Note + that for compatibility with the other instruction formats, the opcode + is shifted left by 2 bits. Bits 0 and 1 must have value zero for this + format.
        uint24_vbrProvides the slot number of the result type + of the instruction
        uint32_vbrThe number of operands that follow.
        uint32_vbr+The slot number of the value(s) for the + operand(s). 1
        + Notes: +
          +
        1. Note that if the instruction is a getelementptr and the type of + the operand is a sequential type (array or pointer) then the slot + number is shifted up two bits and the low order bits will encode the + type of index used, as follows: 0=uint, 1=int, 2=ulong, 3=long.
        2. +
        +

        Instruction Format 1

        +

        This format encodes the opcode, type and a single operand into a + single uint32_vbr as follows:

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        BitsTypeField Description
        0-1constant "1"These two bits must be the value 1 which + identifies this as an instruction of format 1.
        2-7opcodeSpecifies the opcode of the instruction. Note + that the maximum opcode value is 63.
        8-19unsignedSpecifies the slot number of the type for + this instruction. Maximum slot number is 212-1=4095.
        20-31unsignedSpecifies the slot number of the value for + the first operand. Maximum slot number is 212-1=4095. Note + that the value 212-1 denotes zero operands.
        +

        Instruction Format 2

        +

        This format encodes the opcode, type and two operands into a single uint32_vbr as follows:

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        BitsTypeField Description
        0-1constant "2"These two bits must be the value 2 which + identifies this as an instruction of format 2.
        2-7opcodeSpecifies the opcode of the instruction. Note + that the maximum opcode value is 63.
        8-15unsignedSpecifies the slot number of the type for + this instruction. Maximum slot number is 28-1=255.
        16-23unsignedSpecifies the slot number of the value for + the first operand. Maximum slot number is 28-1=255.
        24-31unsignedSpecifies the slot number of the value for + the second operand. Maximum slot number is 28-1=255.
        +

        Instruction Format 3

        +

        This format encodes the opcode, type and three operands into a + single uint32_vbr as follows:

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        BitsTypeField Description
        0-1constant "3"These two bits must be the value 3 which + identifies this as an instruction of format 3.
        2-7opcodeSpecifies the opcode of the instruction. Note + that the maximum opcode value is 63.
        8-13unsignedSpecifies the slot number of the type for + this instruction. Maximum slot number is 26-1=63.
        14-19unsignedSpecifies the slot number of the value for + the first operand. Maximum slot number is 26-1=63.
        20-25unsignedSpecifies the slot number of the value for + the second operand. Maximum slot number is 26-1=63.
        26-31unsignedSpecifies the slot number of the value for + the third operand. Maximum slot number is 26-1=63.
        +
        + + +
        +

        A symbol table can be put out in conjunction with a module or a function. + A symbol table is a list of type planes. Each type plane starts with the number + of entries in the plane and the type plane's slot number (so the type + can be looked up in the global type pool). For each entry in a type + plane, the slot number of the value and the name associated with that + value are written. The format is given in the table below.

        + + + + + + + + + + + + + + + + + + + + + + + +
        TypeField Description
        block
        +
        Symbol Table Identifier (0x04)
        uint32_vbrNumber of entries in type plane
        symtab_entry*Provides the slot number of the type and its + name.
        symtab_plane*A type plane containing value slot number and + name for all values of the same type.
        +
        + + +
        +

        A symbol table plane provides the symbol table entries for all + values of a common type. The encoding is given in the following table:

        + + + + + + + + + + + + + + + + + + + +
        TypeField Description
        uint32_vbrNumber of entries in this plane.
        uint32_vbrSlot number of type for this plane.
        symtab_entry+The symbol table entries for this plane.
        +
        + + +
        +

        A symbol table entry provides the assocation between a type or + value's slot number and the name given to that type or value. The + format is given in the following table:

        + + + + + + + + + + + + + + + + + + + +
        TypeField Description
        uint24_vbrSlot number of the type or value being given + a name.
        uint32_vbrLength of the character array that follows.
        char+The characters of the name.
        +
        + + + +
        +

        This section describes the differences in the Bytecode Format across + LLVM + versions. The versions are listed in reverse order because it assumes + the current version is as documented in the previous sections. Each + section here + describes the differences between that version and the one that follows. +

        +
        + + + +
        Type Derives From Value
        +
        +

        In version 1.2, the Type class in the LLVM IR derives from the Value + class. This is not the case in version 1.3. Consequently, in version + 1.2 the notion of a "Type Type" was used to write out values that were + Types. The types always occuped plane 12 (corresponding to the + TypeTyID) of any type planed set of values. In 1.3 this representation + is not convenient because the TypeTyID (12) is not present and its + value is now used for LabelTyID. Consequently, the data structures + written that involve types do so by writing all the types first and + then each of the value planes according to those types. In version 1.2, + the types would have been written intermingled with the values.

        +
        + +
        Restricted getelementptr Types
        +
        +

        In version 1.2, the getelementptr instruction required a ubyte type + index for accessing a structure field and a long type index for + accessing an array element. Consequently, it was only possible to + access structures of 255 or fewer elements. Starting in version 1.3, + this restriction was lifted. Structures must now be indexed with uint + constants. Arrays may now be indexed with int, uint, long, or ulong + typed values. The consequence of this was that the bytecode format had + to change in order to accommodate the larger range of structure indices.

        +
        + +
        Short Block Headers
        +
        +

        In version 1.2, block headers were always 8 bytes being comprised of + both an unsigned integer type and an unsigned integer size. For very + small modules, these block headers turn out to be a large fraction of + the total bytecode file size. In an attempt to make these small files + smaller, the type and size information was encoded into a single + unsigned integer (4 bytes) comprised of 5 bits for the block type + (maximum 31 block types) and 27 bits for the block size (max + ~134MBytes). These limits seemed sufficient for any blocks or sizes + forseen in the future. Note that the module block, which encloses all + the other blocks is still written as 8 bytes since bytecode files + larger than 134MBytes might be possible.

        +
        + +
        Dependent Libraries and Target Triples
        +
        +

        In version 1.2, the bytecode format does not store module's target + triple or dependent. These fields have been added to the end of the module global info block. The purpose of these + fields is to allow a front end compiler to specifiy that the generated + module is specific to a particular target triple (operating + system/manufacturer/processor) which makes it non-portable; and to + allow front end compilers to specify the list of libraries that the + module depends on for successful linking.

        +
        + +
        Types Restricted to 24-bits
        +
        +

        In version 1.2, type slot identifiers were written as 32-bit VBR + quantities. In 1.3 this has been reduced to 24-bits in order to ensure + that it is not possible to overflow the type field of a global variable + definition. 24-bits for type slot numbers is deemed sufficient for any + practical use of LLVM.

        +
        + + + + +
        Explicit Primitive Zeros
        +
        +

        In version 1.1, the zero value for primitives was explicitly encoded + into the bytecode format. Since these zero values are constant values + in the LLVM IR and never change, there is no reason to explicitly + encode them. This explicit encoding was removed in version 1.2.

        +
        + +
        Inconsistent Module Global Info
        +
        +

        In version 1.1, the Module Global Info block was not aligned causing + the next block to be read in on an unaligned boundary. This problem was + corrected in version 1.2.
        +
        +

        +
        + + +
        +

        None. Version 1.0 and 1.1 bytecode formats are identical.

        +
        + +
        +
        Valid CSS! + Valid HTML 4.01! + Reid Spencer and Chris Lattner
        + The LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + + + Index: llvm-www/releases/1.3/docs/CFEBuildInstrs.html diff -c /dev/null llvm-www/releases/1.3/docs/CFEBuildInstrs.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/CFEBuildInstrs.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,309 ---- + + + + + + Bootstrapping the LLVM C/C++ Front-End + + + +
        + Bootstrapping the LLVM C/C++ Front-End +
        + +
          +
        1. A Cautionary Note + +
        2. +
        3. Instructions
        4. +
        5. License Information
        6. +
        + +
        +

        Written by Brian R. Gaeke and + Chris Lattner

        +
        + + + + + +
        +

        This document is intended to explain the process of building the + LLVM C/C++ front-end, based on GCC 3.4, from its source code. You + would have to do this, for example, if you are porting LLVM to a new + architecture or operating system.

        + +

        NOTE: This is currently a somewhat fragile, error-prone + process, and you should only try to do it if:

        + +
          +
        1. you really, really, really can't use the binaries we distribute
        2. +
        3. you need GCC to fix some of the header files on your system
        4. +
        5. you are an elite GCC hacker.
        6. +
        + +

        We welcome patches to help make this process simpler.

        +
        + + + + + +
        +

        If you are building LLVM and the C front-end under Cygwin, please note that + the LLVM and GCC makefiles do not correctly handle spaces in paths. To deal + with this issue, make sure that your LLVM and GCC source and build trees are + located in a top-level directory (like /cygdrive/c/llvm and + /cygdrive/c/llvm-cfrontend), not in a directory that contains a space + (which includes your "home directory", because it lives under the "Documents + and Settings" directory). We welcome patches to fix this issue. +

        +
        + + + + + +
        +

        +

          +
        1. Configure and build the LLVM libraries and tools using:

          +
          +  % cd llvm
          +  % ./configure [options...]
          +  % gmake 
          + 
          +

          This will build all of the LLVM tools and libraries, but you will see + warnings about missing the C front-end (certain runtime libraries can't + be built without it). Ignore these warnings for now.

        2. + +
        3. Add the directory containing the tools to your PATH.

          +
          +  % set path = ( `cd llvm/tools/Debug && pwd` $path )
          + 
        4. + +
        5. Unpack the C/C++ front-end source into cfrontend/src.

        6. + +
        7. Make "build" and "install" directories as siblings of the "src" + tree.

          +
          +  % pwd
          +  /usr/local/example/cfrontend/src
          +  % cd ..
          +  % mkdir build install
          +  % set CFEINSTALL = `pwd`/install
          + 
        8. + + +
        9. Configure, build, and install the C front-end:

          + +

          + Linux/x86:
          + MacOS X/PowerPC (requires dlcompat library): +

          + +
          +  % cd build
          +  % ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls --disable-shared \
          +    --enable-languages=c,c++
          +  % gmake
          +  % setenv LLVM_LIB_SEARCH_PATH `pwd`/gcc 
          +  % gmake all; gmake install
          + 
          + +

          Cygwin/x86:

          + +
          +  % cd build
          +  % ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls --disable-shared \
          +    --enable-languages=c,c++ --disable-c-mbchar
          +  % gmake
          +  % setenv LLVM_LIB_SEARCH_PATH `pwd`/gcc 
          +  % gmake all; gmake install
          + 
          + +

          Solaris/SPARC:

          + +

          + For Solaris/SPARC, LLVM only supports the SPARC V9. Therefore, the + configure command line should specify sparcv9, as shown below. Also, + note that Solaris has trouble with various wide (multibyte) character + functions from C as referenced from C++, so we typically configure with + --disable-c-mbchar (cf. Bug 206). +

          + +
          +  % cd build
          +  % ../src/configure --prefix=$CFEINSTALL --disable-threads --disable-nls \
          +    --disable-shared --enable-languages=c,c++ --host=sparcv9-sun-solaris2.8 \
          +    --disable-c-mbchar
          +  % gmake
          +  % setenv LLVM_LIB_SEARCH_PATH `pwd`/gcc 
          +  % gmake all; gmake install
          + 
          + +

          Common Problem: You may get error messages regarding the fact + that LLVM does not support inline assembly. Here are two common + fixes:

          + +
            +
          • Fix 1: If you have system header files that include + inline assembly, you may have to modify them to remove the inline + assembly, and install the modified versions in + $CFEINSTALL/target-triplet/sys-include.

          • + +
          • Fix 2: If you are building the C++ front-end on a CPU we + haven't tried yet, you will probably have to edit the appropriate + version of atomicity.h under + src/libstdc++-v3/config/cpu/name-of-cpu/atomicity.h + and apply a patch so that it does not use inline assembly.
          • +
          + +

          Porting to a new architecture: If you are porting the new front-end + to a new architecture, or compiling in a different configuration that we have + previously, there are probably several changes you will have to make to the GCC + target to get it to work correctly. These include:

          + +

            +
          • Often targets include special or assembler linker flags which + gccas/gccld does not understand. In general, these can + just be removed.
          • +
          • LLVM currently does not support any floating point values other than + 32-bit and 64-bit IEEE floating point. The primary effect of this is + that you may have to map "long double" onto "double".
          • +
          • The profiling hooks in GCC do not apply at all to the LLVM front-end. + These may need to be disabled.
          • +
          • No inline assembly for position independent code. At the LLVM level, + everything is position independent.
          • +
          • We handle .init and .fini differently.
          • +
          • You may have to disable multilib support in your target. Using multilib + support causes the GCC compiler driver to add a lot of "-L" + options to the link line, which do not relate to LLVM and confuse + gccld. To disable multilibs, delete any + MULTILIB_OPTIONS lines from your target files.
          • +
          • Did we mention that we don't support inline assembly? You'll probably + have to add some fixinclude hacks to disable it in the system + headers.
          • +
          +
        10. + +
        11. Go back into the LLVM source tree proper. Rerun configure, using + the --with-llvmgccdir=$CFEINSTALL option to specify the path + to the newly built C front-end.

        12. + +
        13. If you edited header files during the C/C++ front-end build as + described in "Fix 1" above, you must now copy those header files from + $CFEINSTALL/target-triplet/sys-include to + $CFEINSTALL/lib/gcc/target-triplet/3.4-llvm/include. + (This should be the "include" directory in the same directory as the + libgcc.a library, which you can find by running + $CFEINSTALL/bin/gcc --print-libgcc-file-name.)

        14. + +
        15. Rebuild your CVS tree. This shouldn't cause the whole thing to be + rebuilt, but it should build the runtime libraries. After the tree is + built, install the runtime libraries into your C front-end build tree. + These are the commands you need.

          +
          +  % gmake
          +  % mkdir $CFEINSTALL/bytecode-libs
          +  % gmake -C runtime install-bytecode
          +  % setenv LLVM_LIB_SEARCH_PATH $CFEINSTALL/bytecode-libs
          + 
        16. + +
        17. Test the newly-installed C frontend by one or more of the + following means:

          +
            +
          • compiling and running a "hello, LLVM" program in C and C++.
          • +
          • running the tests under test/Programs using gmake -C + test/Programs
          • +
        18. +
        +
        + + + + +
        +

        + The LLVM GCC frontend is licensed to you under the GNU General Public License + and the GNU Lesser General Public License. Please see the files COPYING and + COPYING.LIB for more details. +

        + +

        + The software also has the following additional copyrights: +

        + +
        + 
        + Copyright (c) 2003, 2004 University of Illinois at Urbana-Champaign.
        + All rights reserved.
        + 
        + Developed by:
        + 
        +     LLVM Team
        + 
        +     University of Illinois at Urbana-Champaign
        + 
        +     http://llvm.cs.uiuc.edu
        + 
        + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
        + FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
        + CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
        + SOFTWARE.
        + 
        + Copyright (c) 1994
        + Hewlett-Packard Company
        + 
        + Permission to use, copy, modify, distribute and sell this software
        + and its documentation for any purpose is hereby granted without fee,
        + provided that the above copyright notice appear in all copies and
        + that both that copyright notice and this permission notice appear
        + in supporting documentation.  Hewlett-Packard Company makes no
        + representations about the suitability of this software for any
        + purpose.  It is provided "as is" without express or implied warranty.
        + 
        + Copyright (c) 1996, 1997, 1998, 1999
        + Silicon Graphics Computer Systems, Inc.
        + 
        + Permission to use, copy, modify, distribute and sell this software
        + and its documentation for any purpose is hereby granted without fee,
        + provided that the above copyright notice appear in all copies and
        + that both that copyright notice and this permission notice appear
        + in supporting documentation.  Silicon Graphics makes no
        + representations about the suitability of this software for any
        + purpose.  It is provided "as is" without express or implied warranty.
        + 
        +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Brian Gaeke
        + LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + + + Index: llvm-www/releases/1.3/docs/CodeGenerator.html diff -c /dev/null llvm-www/releases/1.3/docs/CodeGenerator.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/CodeGenerator.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,644 ---- + + + + The LLVM Target-Independent Code Generator + + + + +
        + The LLVM Target-Independent Code Generator +
        + +
          +
        1. Introduction + +
        2. +
        3. Target description classes + +
        4. +
        5. Machine code description classes + +
        6. +
        7. Target-independent code generation algorithms +
        8. +
        9. Target description implementations + +
        10. + +
        + +
        +

        Written by Chris Lattner

        +
        + +
        +

        Warning: This is a work in progress.

        +
        + + + + + +
        + +

        The LLVM target-independent code generator is a framework that provides a + suite of reusable components for translating the LLVM internal representation to + the machine code for a specified target -- either in assembly form (suitable for + a static compiler) or in binary machine code format (usable for a JIT compiler). + The LLVM target-independent code generator consists of five main components:

        + +
          +
        1. Abstract target description interfaces which + capture important properties about various aspects of the machine, independently + of how they will be used. These interfaces are defined in + include/llvm/Target/.
        2. + +
        3. Classes used to represent the machine code being + generated for a target. These classes are intended to be abstract enough to + represent the machine code for any target machine. These classes are + defined in include/llvm/CodeGen/.
        4. + +
        5. Target-independent algorithms used to implement + various phases of native code generation (register allocation, scheduling, stack + frame representation, etc). This code lives in lib/CodeGen/.
        6. + +
        7. Implementations of the abstract target description + interfaces for particular targets. These machine descriptions make use of + the components provided by LLVM, and can optionally provide custom + target-specific passes, to build complete code generators for a specific target. + Target descriptions live in lib/Target/.
        8. + +
        9. The target-independent JIT components. The LLVM JIT is + completely target independent (it uses the TargetJITInfo structure to + interface for target-specific issues. The code for the target-independent + JIT lives in lib/ExecutionEngine/JIT.
        10. + +
        + +

        + Depending on which part of the code generator you are interested in working on, + different pieces of this will be useful to you. In any case, you should be + familiar with the target description and machine code representation classes. If you want to add + a backend for a new target, you will need to implement the + target description classes for your new target and understand the LLVM code representation. If you are interested in + implementing a new code generation algorithm, it + should only depend on the target-description and machine code representation + classes, ensuring that it is portable. +

        + +
        + + + + +
        + +

        The two pieces of the LLVM code generator are the high-level interface to the + code generator and the set of reusable components that can be used to build + target-specific backends. The two most important interfaces (TargetMachine and TargetData classes) are the only ones that are + required to be defined for a backend to fit into the LLVM system, but the others + must be defined if the reusable code generator components are going to be + used.

        + +

        This design has two important implications. The first is that LLVM can + support completely non-traditional code generation targets. For example, the C + backend does not require register allocation, instruction selection, or any of + the other standard components provided by the system. As such, it only + implements these two interfaces, and does its own thing. Another example of a + code generator like this is a (purely hypothetical) backend that converts LLVM + to the GCC RTL form and uses GCC to emit machine code for a target.

        + +

        This design also implies that it is possible to design and + implement radically different code generators in the LLVM system that do not + make use of any of the built-in components. Doing so is not recommended at all, + but could be required for radically different targets that do not fit into the + LLVM machine description model: programmable FPGAs for example.

        + +

        Important Note: For historical reasons, the LLVM SparcV9 code + generator uses almost entirely different code paths than described in this + document. For this reason, there are some deprecated interfaces (such as + TargetRegInfo and TargetSchedInfo), which are only used by the + V9 backend and should not be used by any other targets. Also, all code in the + lib/Target/SparcV9 directory and subdirectories should be considered + deprecated, and should not be used as the basis for future code generator work. + The SparcV9 backend is slowly being merged into the rest of the + target-independent code generators, but this is a low-priority process with no + predictable completion date.

        + +
        + + + + +
        + +

        The LLVM target-indendent code generator is designed to support efficient and + quality code generation for standard register-based microprocessors. Code + generation in this model is divided into the following stages:

        + +
          +
        1. Instruction Selection - Determining an efficient implementation of the + input LLVM code in the target instruction set. This stage produces the initial + code for the program in the target instruction set, then makes use of virtual + registers in SSA form and physical registers that represent any required + register assignments due to target constraints or calling conventions.
        2. + +
        3. SSA-based Machine Code Optimizations - This (optional) stage consists + of a series of machine-code optimizations that operate on the SSA-form produced + by the instruction selector. Optimizations like modulo-scheduling, normal + scheduling, or peephole optimization work here.
        4. + +
        5. Register Allocation - The target code is transformed from an infinite + virtual register file in SSA form to the concrete register file used by the + target. This phase introduces spill code and eliminates all virtual register + references from the program.
        6. + +
        7. Prolog/Epilog Code Insertion - Once the machine code has been + generated for the function and the amount of stack space required is known (used + for LLVM alloca's and spill slots), the prolog and epilog code for the function + can be inserted and "abstract stack location references" can be eliminated. + This stage is responsible for implementing optimizations like frame-pointer + elimination and stack packing.
        8. + +
        9. Late Machine Code Optimizations - Optimizations that operate on + "final" machine code can go here, such as spill code scheduling and peephole + optimizations.
        10. + +
        11. Code Emission - The final stage actually outputs the code for + the current function, either in the target assembler format or in machine + code.
        12. + +
        + +

        + The code generator is based on the assumption that the instruction selector will + use an optimal pattern matching selector to create high-quality sequences of + native instructions. Alternative code generator designs based on pattern + expansion and + aggressive iterative peephole optimization are much slower. This design + permits efficient compilation (important for JIT environments) and + aggressive optimization (used when generating code offline) by allowing + components of varying levels of sophisication to be used for any step of + compilation.

        + +

        + In addition to these stages, target implementations can insert arbitrary + target-specific passes into the flow. For example, the X86 target uses a + special pass to handle the 80x87 floating point stack architecture. Other + targets with unusual requirements can be supported with custom passes as needed. +

        + +
        + + + + + +
        + +

        The target description classes require a detailed description of the target + architecture. These target descriptions often have a large amount of common + information (e.g., an add instruction is almost identical to a sub instruction). + In order to allow the maximum amount of commonality to be factored out, the LLVM + code generator uses the TableGen tool to + describe big chunks of the target machine, which allows the use of domain- and + target-specific abstractions to reduce the amount of repetition. +

        + +
        + + + + + +
        + +

        The LLVM target description classes (which are located in the + include/llvm/Target directory) provide an abstract description of the + target machine, independent of any particular client. These classes are + designed to capture the abstract properties of the target (such as what + instruction and registers it has), and do not incorporate any particular pieces + of code generation algorithms (these interfaces do not take interference graphs + as inputs or other algorithm-specific data structures).

        + +

        All of the target description classes (except the TargetData class) are designed to be subclassed by + the concrete target implementation, and have virtual methods implemented. To + get to these implementations, the TargetMachine class provides accessors that + should be implemented by the target.

        + +
        + + + + +
        + +

        The TargetMachine class provides virtual methods that are used to + access the target-specific implementations of the various target description + classes (with the getInstrInfo, getRegisterInfo, + getFrameInfo, ... methods). This class is designed to be specialized by + a concrete target implementation (e.g., X86TargetMachine) which + implements the various virtual methods. The only required target description + class is the TargetData class, but if the + code generator components are to be used, the other interfaces should be + implemented as well.

        + +
        + + + + + +
        + +

        The TargetData class is the only required target description class, + and it is the only class that is not extensible (it cannot be derived from). It + specifies information about how the target lays out memory for structures, the + alignment requirements for various data types, the size of pointers in the + target, and whether the target is little- or big-endian.

        + +
        + + + + + +
        + +

        The MRegisterInfo class (which will eventually be renamed to + TargetRegisterInfo) is used to describe the register file of the + target and any interactions between the registers.

        + +

        Registers in the code generator are represented in the code generator by + unsigned numbers. Physical registers (those that actually exist in the target + description) are unique small numbers, and virtual registers are generally + large.

        + +

        Each register in the processor description has an associated + MRegisterDesc entry, which provides a textual name for the register + (used for assembly output and debugging dumps), a set of aliases (used to + indicate that one register overlaps with another), and some flag bits. +

        + +

        In addition to the per-register description, the MRegisterInfo class + exposes a set of processor specific register classes (instances of the + TargetRegisterClass class). Each register class contains sets of + registers that have the same properties (for example, they are all 32-bit + integer registers). Each SSA virtual register created by the instruction + selector has an associated register class. When the register allocator runs, it + replaces virtual registers with a physical register in the set.

        + +

        + The target-specific implementations of these classes is auto-generated from a TableGen description of the register file. +

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

        + 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 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. +

        + +
        + + + + +
        + +

        Target machine instructions are represented as instances of the + MachineInstr class. This class is an extremely abstract way of + representing machine instructions. In particular, all it keeps track of is + an opcode number and some number of operands.

        + +

        The opcode number is an simple unsigned number that only has meaning to a + specific backend. All of the instructions for a target should be defined in + the *InstrInfo.td file for the target, and the opcode enum values + are autogenerated from this description. The MachineInstr class does + not have any information about how to intepret the instruction (i.e., what the + semantics of the instruction are): for that you must refer to the + TargetInstrInfo class.

        + +

        The operands of a machine instruction can be of several different types: + they can be a register reference, constant integer, basic block reference, etc. + In addition, a machine operand should be marked as a def or a use of the value + (though only registers are allowed to be defs).

        + +

        By convention, the LLVM code generator orders instruction operands so that + all register definitions come before the register uses, even on architectures + that are normally printed in other orders. For example, the sparc add + instruction: "add %i1, %i2, %i3" adds the "%i1", and "%i2" registers + and stores the result into the "%i3" register. In the LLVM code generator, + the operands should be stored as "%i3, %i1, %i2": with the destination + first.

        + +

        Keeping destination operands at the beginning of the operand list has several + advantages. In particular, the debugging printer will print the instruction + like this:

        + +
        +   %r3 = add %i1, %i2
        + 
        + +

        If the first operand is a def, and it is also easier to create instructions whose only def is the first + operand.

        + +
        + + + + +
        + +

        Machine instructions are created by using the BuildMI functions, + located in the include/llvm/CodeGen/MachineInstrBuilder.h file. The + BuildMI functions make it easy to build arbitrary machine + instructions. Usage of the BuildMI functions look like this: +

        + +
        +   // Create a 'DestReg = mov 42' (rendered in X86 assembly as 'mov DestReg, 42')
        +   // instruction.  The '1' specifies how many operands will be added.
        +   MachineInstr *MI = BuildMI(X86::MOV32ri, 1, DestReg).addImm(42);
        + 
        +   // Create the same instr, but insert it at the end of a basic block.
        +   MachineBasicBlock &MBB = ...
        +   BuildMI(MBB, X86::MOV32ri, 1, DestReg).addImm(42);
        + 
        +   // Create the same instr, but insert it before a specified iterator point.
        +   MachineBasicBlock::iterator MBBI = ...
        +   BuildMI(MBB, MBBI, X86::MOV32ri, 1, DestReg).addImm(42);
        + 
        +   // Create a 'cmp Reg, 0' instruction, no destination reg.
        +   MI = BuildMI(X86::CMP32ri, 2).addReg(Reg).addImm(0);
        +   // Create an 'sahf' instruction which takes no operands and stores nothing.
        +   MI = BuildMI(X86::SAHF, 0);
        + 
        +   // Create a self looping branch instruction.
        +   BuildMI(MBB, X86::JNE, 1).addMBB(&MBB);
        + 
        + +

        + The key thing to remember with the BuildMI functions is that you have + to specify the number of operands that the machine instruction will take + (allowing efficient memory allocation). Also, if operands default to be uses + of values, not definitions. If you need to add a definition operand (other + than the optional destination register), you must explicitly mark it as such. +

        + +
        + + + + +
        + +

        One important issue that the code generator needs to be aware of is the + presence of fixed registers. In particular, there are often places in the + instruction stream where the register allocator must arrange for a + particular value to be in a particular register. This can occur due to + limitations in the instruction set (e.g., the X86 can only do a 32-bit divide + with the EAX/EDX registers), or external factors like calling + conventions. In any case, the instruction selector should emit code that + copies a virtual register into or out of a physical register when needed.

        + +

        For example, consider this simple LLVM example:

        + +
        +   int %test(int %X, int %Y) {
        +     %Z = div int %X, %Y
        +     ret int %Z
        +   }
        + 
        + +

        The X86 instruction selector produces this machine code for the div + and ret (use + "llc X.bc -march=x86 -print-machineinstrs" to get this):

        + +
        +         ;; Start of div
        +         %EAX = mov %reg1024           ;; Copy X (in reg1024) into EAX
        +         %reg1027 = sar %reg1024, 31
        +         %EDX = mov %reg1027           ;; Sign extend X into EDX
        +         idiv %reg1025                 ;; Divide by Y (in reg1025)
        +         %reg1026 = mov %EAX           ;; Read the result (Z) out of EAX
        + 
        +         ;; Start of ret
        +         %EAX = mov %reg1026           ;; 32-bit return value goes in EAX
        +         ret
        + 
        + +

        By the end of code generation, the register allocator has coallesced + the registers and deleted the resultant identity moves, producing the + following code:

        + +
        +         ;; X is in EAX, Y is in ECX
        +         mov %EAX, %EDX
        +         sar %EDX, 31
        +         idiv %ECX
        +         ret 
        + 
        + +

        This approach is extremely general (if it can handle the X86 architecture, + it can handle anything!) and allows all of the target specific + knowledge about the instruction stream to be isolated in the instruction + selector. Note that physical registers should have a short lifetime for good + code generation, and all physical registers are assumed dead on entry and + exit of basic blocks (before register allocation). Thus if you need a value + to be live across basic block boundaries, it must live in a virtual + register.

        + +
        + + + + +
        + +

        MachineInstr's are initially instruction selected in SSA-form, and + are maintained in SSA-form until register allocation happens. For the most + part, this is trivially simple since LLVM is already in SSA form: LLVM PHI nodes + become machine code PHI nodes, and virtual registers are only allowed to have a + single definition.

        + +

        After register allocation, machine code is no longer in SSA-form, as there + are no virtual registers left in the code.

        + +
        + + + + + +
        + +

        This section of the document explains any features or design decisions that + are specific to the code generator for a particular target.

        + +
        + + + + + +
        + +

        + The X86 code generator lives in the lib/Target/X86 directory. This + code generator currently targets a generic P6-like processor. As such, it + produces a few P6-and-above instructions (like conditional moves), but it does + not make use of newer features like MMX or SSE. In the future, the X86 backend + will have subtarget support added for specific processor families and + implementations.

        + +
        + + + + +
        + +

        + The x86 has a very, uhm, flexible, way of accessing memory. It is capable of + forming memory addresses of the following expression directly in integer + instructions (which use ModR/M addressing):

        + +
        +    Base+[1,2,4,8]*IndexReg+Disp32
        + 
        + +

        Wow, that's crazy. In order to represent this, LLVM tracks no less that 4 + operands for each memory operand of this form. This means that the "load" form + of 'mov' has the following "Operands" in this order:

        + +
        + Index:        0     |    1        2       3           4
        + Meaning:   DestReg, | BaseReg,  Scale, IndexReg, Displacement
        + OperandTy: VirtReg, | VirtReg, UnsImm, VirtReg,   SignExtImm
        + 
        + +

        Stores and all other instructions treat the four memory operands in the same + way, in the same order.

        + +
        + + + + +
        + +

        + 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:

        + +

        + ADD8rr -> add, 8-bit register, 8-bit register
        + 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 +

        + +
        + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
        + The LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + + + Index: llvm-www/releases/1.3/docs/CodingStandards.html diff -c /dev/null llvm-www/releases/1.3/docs/CodingStandards.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/CodingStandards.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,624 ---- + + + + + A Few Coding Standards + + + +
        + A Few Coding Standards +
        + +
          +
        1. Introduction
        2. +
        3. Mechanical Source Issues +
            +
          1. Source Code Formatting +
              +
            1. Commenting
            2. +
            3. Comment Formatting
            4. +
            5. #include Style
            6. +
            7. Source Code Width
            8. +
            9. Use Spaces Instead of Tabs
            10. +
            11. Indent Code Consistently
            12. +
          2. +
          3. Compiler Issues +
              +
            1. Treat Compiler Warnings Like + Errors
            2. +
            3. Write Portable Code
            4. +
          4. +
        4. +
        5. Style Issues +
            +
          1. The High Level Issues +
              +
            1. A Public Header File is a + Module
            2. +
            3. #include as Little as Possible
            4. +
            5. Keep "internal" Headers + Private
            6. +
          2. +
          3. The Low Level Issues +
              +
            1. Assert Liberally
            2. +
            3. Prefer Preincrement
            4. +
            5. Avoid std::endl
            6. +
            7. Exploit C++ to its Fullest
            8. +
          4. +
        6. +
        7. See Also
        8. +
        + +
        +

        Written by Chris Lattner

        +
        + + + + + + +
        + +

        This document attempts to describe a few coding standards that are being used + in the LLVM source tree. Although no coding standards should be regarded as + absolute requirements to be followed in all instances, coding standards can be + useful.

        + +

        This document intentionally does not prescribe fixed standards for religious + issues such as brace placement and space usage. For issues like this, follow + the golden rule:

        + +
        + +

        If you are adding a significant body of source to a + project, feel free to use whatever style you are most comfortable with. If you + are extending, enhancing, or bug fixing already implemented code, use the style + that is already being used so that the source is uniform and easy to + follow.

        + +
        + +

        The ultimate goal of these guidelines is the increase readability and + maintainability of our common source base. If you have suggestions for topics to + be included, please mail them to Chris.

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

        Comments are one critical part of readability and maintainability. Everyone + knows they should comment, so should you. :) Although we all should probably + comment our code more than we do, there are a few very critical places that + documentation is very useful:

        + + File Headers + +

        Every source file should have a header on it that + describes the basic purpose of the file. If a file does not have a header, it + should not be checked into CVS. Most source trees will probably have a standard + file header format. The standard format for the LLVM source tree looks like + this:

        + +
        +
        + //===-- llvm/Instruction.h - Instruction class definition -------*- 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 declaration of the Instruction class, which is the
        + // base class for all of the VM instructions.
        + //
        + //===----------------------------------------------------------------------===//
        + 
        +
        + +

        A few things to note about this particular format: The "-*- C++ + -*-" string on the first line is there to tell Emacs that the source file + is a C++ file, not a C file (Emacs assumes .h files are C files by default). + Note that this tag is not necessary in .cpp files. The name of the file is also + on the first line, along with a very short description of the purpose of the + file. This is important when printing out code and flipping though lots of + pages.

        + +

        The next section in the file is a concise note that defines the license that + the file is released under. This makes it perfectly clear what terms the source + code can be distributed under.

        + +

        The main body of the description does not have to be very long in most cases. + Here it's only two lines. If an algorithm is being implemented or something + tricky is going on, a reference to the paper where it is published should be + included, as well as any notes or "gotchas" in the code to watch out for.

        + + Class overviews + +

        Classes are one fundemental part of a good object oriented design. As such, + a class definition should have a comment block that explains what the class is + used for... if it's not obvious. If it's so completely obvious your grandma + could figure it out, it's probably safe to leave it out. Naming classes + something sane goes a long ways towards avoiding writing documentation. :)

        + + + Method information + +

        Methods defined in a class (as well as any global functions) should also be + documented properly. A quick note about what it does any a description of the + borderline behaviour is all that is necessary here (unless something + particularly tricky or insideous is going on). The hope is that people can + figure out how to use your interfaces without reading the code itself... that is + the goal metric.

        + +

        Good things to talk about here are what happens when something unexpected + happens: does the method return null? Abort? Format your hard disk?

        + +
        + + + + +
        + +

        In general, prefer C++ style (//) comments. They take less space, + require less typing, don't have nesting problems, etc. There are a few cases + when it is useful to use C style (/* */) comments however:

        + +
          +
        1. When writing a C code: Obviously if you are writing C code, use C style + comments. :)
        2. +
        3. When writing a header file that may be #included by a C source file.
        4. +
        5. When writing a source file that is used by a tool that only accepts C + style comments.
        6. +
        + +

        To comment out a large block of code, use #if 0 and #endif. + These nest properly and are better behaved in general than C style comments.

        + +
        + + + + +
        + +

        Immediately after the header file comment (and + include guards if working on a header file), the minimal list of #includes required by the + file should be listed. We prefer these #includes to be listed in this + order:

        + +
          +
        1. Main Module header
        2. +
        3. Local/Private Headers
        4. +
        5. llvm/*
        6. +
        7. llvm/Analysis/*
        8. +
        9. llvm/Assembly/*
        10. +
        11. llvm/Bytecode/*
        12. +
        13. llvm/CodeGen/*
        14. +
        15. ...
        16. +
        17. Support/*
        18. +
        19. Config/*
        20. +
        21. System #includes
        22. +
        + +

        ... and each catagory should be sorted by name.

        + +

        The "Main Module Header" file applies to .cpp file + which implement an interface defined by a .h file. This #include should always + be included first regardless of where it lives on the file system. By + including a header file first in the .cpp files that implement the interfaces, + we ensure that the header does not have any hidden dependencies which are not + explicitly #included in the header, but should be. It is also a form of + documentation in the .cpp file to indicate where the interfaces it implements + are defined.

        + +
        + + + + +
        + +

        Write your code to fit within 80 columns of text. This helps those of us who + like to print out code and look at your code in an xterm without resizing + it.

        + +
        + + + + +
        + +

        In all cases, prefer spaces to tabs in source files. People have different + prefered indentation levels, and different styles of indentation that they + like... this is fine. What isn't is that different editors/viewers expand tabs + out to different tab stops. This can cause your code to look completely + unreadable, and it is not worth dealing with.

        + +

        As always, follow the Golden Rule above: follow the + style of existing code if your are modifying and extending it. If you like four + spaces of indentation, DO NOT do that in the middle of a chunk of code + with two spaces of indentation. Also, do not reindent a whole source file: it + makes for incredible diffs that are absolutely worthless.

        + +
        + + + + +
        + +

        Okay, your first year of programming you were told that indentation is + important. If you didn't believe and internalize this then, now is the time. + Just do it.

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

        If your code has compiler warnings in it, something is wrong: you aren't + casting values correctly, your have "questionable" constructs in your code, or + you are doing something legitimately wrong. Compiler warnings can cover up + legitimate errors in output and make dealing with a translation unit + difficult.

        + +

        It is not possible to prevent all warnings from all compilers, nor is it + desirable. Instead, pick a standard compiler (like gcc) that provides + a good thorough set of warnings, and stick to them. At least in the case of + gcc, it is possible to work around any spurious errors by changing the + syntax of the code slightly. For example, an warning that annoys me occurs when + I write code like this:

        + +
        +
        + if (V = getValue()) {
        +   ...
        + }
        + 
        +
        + +

        gcc will warn me that I probably want to use the == + operator, and that I probably mistyped it. In most cases, I haven't, and I + really don't want the spurious errors. To fix this particular problem, I + rewrite the code like this:

        + +
        +
        + if ((V = getValue())) {
        +   ...
        + }
        + 
        +
        + +

        ...which shuts gcc up. Any gcc warning that annoys you can + be fixed by massaging the code appropriately.

        + +

        These are the gcc warnings that I prefer to enable: -Wall + -Winline -W -Wwrite-strings -Wno-unused

        + +
        + + + + +
        + +

        In almost all cases, it is possible and within reason to write completely + portable code. If there are cases where it isn't possible to write portable + code, isolate it behind a well defined (and well documented) interface.

        + +

        In practice, this means that you shouldn't assume much about the host + compiler, including its support for "high tech" features like partial + specialization of templates. In fact, Visual C++ 6 could be an important target + for our work in the future, and we don't want to have to rewrite all of our code + to support it.

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

        C++ doesn't do too well in the modularity department. There is no real + encapsulation or data hiding (unless you use expensive protocol classes), but it + is what we have to work with. When you write a public header file (in the LLVM + source tree, they live in the top level "include" directory), you are defining a + module of functionality.

        + +

        Ideally, modules should be completely independent of each other, and their + header files should only include the absolute minimum number of headers + possible. A module is not just a class, a function, or a namespace: it's a collection + of these that defines an interface. This interface may be several + functions, classes or data structures, but the important issue is how they work + together.

        + +

        In general, a module should be implemented with one or more .cpp + files. Each of these .cpp files should include the header that defines + their interface first. This ensure that all of the dependences of the module + header have been properly added to the module header itself, and are not + implicit. System headers should be included after user headers for a + translation unit.

        + +
        + + + + +
        + +

        #include hurts compile time performance. Don't do it unless you + have to, especially in header files.

        + +

        But wait, sometimes you need to have the definition of a class to use it, or + to inherit from it. In these cases go ahead and #include that header file. Be + aware however that there are many cases where you don't need to have the full + definition of a class. If you are using a pointer or reference to a class, you + don't need the header file. If you are simply returning a class instance from a + prototyped function or method, you don't need it. In fact, for most cases, you + simply don't need the definition of a class... and not #include'ing + speeds up compilation.

        + +

        It is easy to try to go too overboard on this recommendation, however. You + must include all of the header files that you are using, either directly + or indirectly (through another header file). To make sure that you don't + accidently forget to include a header file in your module header, make sure to + include your module header first in the implementation file (as mentioned + above). This way there won't be any hidden dependencies that you'll find out + about later...

        + +
        + + + + +
        + +

        Many modules have a complex implementation that causes them to use more than + one implementation (.cpp) file. It is often tempting to put the + internal communication interface (helper classes, extra functions, etc) in the + public module header file. Don't do this. :)

        + +

        If you really need to do something like this, put a private header file in + the same directory as the source files, and include it locally. This ensures + that your private interface remains private and undisturbed by outsiders.

        + +

        Note however, that it's okay to put extra implementation methods a public + class itself... just make them private (or protected), and all is well.

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

        Use the "assert" function to its fullest. Check all of your + preconditions and assumptions, you never know when a bug (not neccesarily even + yours) might be caught early by an assertion, which reduces debugging time + dramatically. The "<cassert>" header file is probably already + included by the header files you are using, so it doesn't cost anything to use + it.

        + +

        To further assist with debugging, make sure to put some kind of error message + in the assertion statement (which is printed if the assertion is tripped). This + helps the poor debugging make sense of why an assertion is being made and + enforced, and hopefully what to do about it. Here is one complete example:

        + +
        +
        + inline Value *getOperand(unsigned i) { 
        +   assert(i < Operands.size() && "getOperand() out of range!");
        +   return Operands[i]; 
        + }
        + 
        +
        + +

        Here are some examples:

        + +
        +
        + assert(Ty->isPointerType() && "Can't allocate a non pointer type!");
        + 
        + assert((Opcode == Shl || Opcode == Shr) && "ShiftInst Opcode invalid!");
        + 
        + assert(idx < getNumSuccessors() && "Successor # out of range!");
        + 
        + assert(V1.getType() == V2.getType() && "Constant types must be identical!");
        + 
        + assert(isa<PHINode>(Succ->front()) && "Only works on PHId BBs!");
        + 
        +
        + +

        You get the idea...

        + +
        + + + + + +
        + +

        Hard fast rule: Preincrement (++X) may be no slower than + postincrement (X++) and could very well be a lot faster than it. Use + preincrementation whenever possible.

        + +

        The semantics of postincrement include making a copy of the value being + incremented, returning it, and then preincrementing the "work value". For + primitive types, this isn't a big deal... but for iterators, it can be a huge + issue (for example, some iterators contains stack and set objects in them... + copying an iterator could invoke the copy ctor's of these as well). In general, + get in the habit of always using preincrement, and you won't have a problem.

        + +
        + + + + +
        + +

        The std::endl modifier, when used with iostreams outputs a newline + to the output stream specified. In addition to doing this, however, it also + flushes the output stream. In other words, these are equivalent:

        + +
        +
        + std::cout << std::endl;
        + std::cout << '\n' << std::flush;
        + 
        +
        + +

        Most of the time, you probably have no reason to flush the output stream, so + it's better to use a literal '\n'.

        + +
        + + + + +
        + +

        C++ is a powerful language. With a firm grasp on its capabilities, you can + make write effective, consise, readable and maintainable code all at the same + time. By staying consistent, you reduce the amount of special cases that need + to be remembered. Reducing the total number of lines of code you write is a + good way to avoid documentation, and avoid giving bugs a place to hide.

        + +

        For these reasons, come to know and love the contents of your local + <algorithm> header file. Know about <functional> and what it can do + for you. C++ is just a tool that wants you to master it. :)

        + +
        + + +
        + See Also +
        + + +
        + +

        A lot of these comments and recommendations have been culled for other + sources. Two particularly important books for our work are:

        + +
          + +
        1. Effective + C++ by Scott Meyers. There is an online version of the book (only some + chapters though) available as well. Also + interesting and useful are "More Effective C++" and "Effective STL" by the same + author.
        2. + +
        3. Large-Scale C++ + Software Design by John Lakos
        4. + +
        + +

        If you get some free time, and you haven't read them: do so, you might learn + something. :)

        + +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
        + LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + + + Index: llvm-www/releases/1.3/docs/CommandLine.html diff -c /dev/null llvm-www/releases/1.3/docs/CommandLine.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/CommandLine.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,1716 ---- + + + + CommandLine 2.0 Library Manual + + + + +
        + CommandLine 2.0 Library Manual +
        + +
          +
        1. Introduction
        2. + +
        3. Quick Start Guide +
            +
          1. Boolean Arguments
          2. +
          3. Argument Aliases
          4. +
          5. Selecting an alternative from a + set of possibilities
          6. +
          7. Named alternatives
          8. +
          9. Parsing a list of options
          10. +
          11. Adding freeform text to help output
          12. +
        4. + +
        5. Reference Guide +
            +
          1. Positional Arguments +
          2. + +
          3. Internal vs External Storage
          4. + +
          5. Option Attributes
          6. + +
          7. Option Modifiers +
          8. + +
          9. Top-Level Classes and Functions +
          10. + +
          11. Builtin parsers +
          12. +
        6. +
        7. Extension Guide +
            +
          1. Writing a custom parser
          2. +
          3. Exploiting external storage
          4. +
          5. Dynamically adding command line + options
          6. +
        8. +
        + +
        +

        Written by Chris Lattner

        +
        + + + + + +
        + +

        This document describes the CommandLine argument processing library. It will + show you how to use it, and what it can do. The CommandLine library uses a + declarative approach to specifying the command line options that your program + takes. By default, these options declarations implicitly hold the value parsed + for the option declared (of course this can be + changed).

        + +

        Although there are a lot of command line argument parsing libraries + out there in many different languages, none of them fit well with what I needed. + By looking at the features and problems of other libraries, I designed the + CommandLine library to have the following features:

        + +
          +
        1. Speed: The CommandLine library is very quick and uses little resources. The + parsing time of the library is directly proportional to the number of arguments + parsed, not the the number of options recognized. Additionally, command line + argument values are captured transparently into user defined global variables, + which can be accessed like any other variable (and with the same + performance).
        2. + +
        3. Type Safe: As a user of CommandLine, you don't have to worry about + remembering the type of arguments that you want (is it an int? a string? a + bool? an enum?) and keep casting it around. Not only does this help prevent + error prone constructs, it also leads to dramatically cleaner source code.
        4. + +
        5. No subclasses required: To use CommandLine, you instantiate variables that + correspond to the arguments that you would like to capture, you don't subclass a + parser. This means that you don't have to write any boilerplate + code.
        6. + +
        7. Globally accessible: Libraries can specify command line arguments that are + automatically enabled in any tool that links to the library. This is possible + because the application doesn't have to keep a "list" of arguments to pass to + the parser. This also makes supporting dynamically + loaded options trivial.
        8. + +
        9. Cleaner: CommandLine supports enum and other types directly, meaning that + there is less error and more security built into the library. You don't have to + worry about whether your integral command line argument accidentally got + assigned a value that is not valid for your enum type.
        10. + +
        11. Powerful: The CommandLine library supports many different types of + arguments, from simple boolean flags to scalars arguments (strings, integers, enums, doubles), to lists of + arguments. This is possible because CommandLine is...
        12. + +
        13. Extensible: It is very simple to add a new argument type to CommandLine. + Simply specify the parser that you want to use with the command line option when + you declare it. Custom parsers are no problem.
        14. + +
        15. Labor Saving: The CommandLine library cuts down on the amount of grunt work + that you, the user, have to do. For example, it automatically provides a + --help option that shows the available command line options for your + tool. Additionally, it does most of the basic correctness checking for + you.
        16. + +
        17. Capable: The CommandLine library can handle lots of different forms of + options often found in real programs. For example, positional arguments, ls style grouping options (to allow processing 'ls + -lad' naturally), ld style prefix + options (to parse '-lmalloc -L/usr/lib'), and interpreter style options.
        18. + +
        + +

        This document will hopefully let you jump in and start using CommandLine in + your utility quickly and painlessly. Additionally it should be a simple + reference manual to figure out how stuff works. If it is failing in some area + (or you want an extension to the library), nag the author, Chris Lattner.

        + +
        + + + + + +
        + +

        This section of the manual runs through a simple CommandLine'ification of a + basic compiler tool. This is intended to show you how to jump into using the + CommandLine library in your own program, and show you some of the cool things it + can do.

        + +

        To start out, you need to include the CommandLine header file into your + program:

        + +
        +   #include "Support/CommandLine.h"
        + 
        + +

        Additionally, you need to add this as the first line of your main + program:

        + +
        + int main(int argc, char **argv) {
        +   cl::ParseCommandLineOptions(argc, argv);
        +   ...
        + }
        + 
        + +

        ... which actually parses the arguments and fills in the variable + declarations.

        + +

        Now that you are ready to support command line arguments, we need to tell the + system which ones we want, and what type of argument they are. The CommandLine + library uses a declarative syntax to model command line arguments with the + global variable declarations that capture the parsed values. This means that + for every command line option that you would like to support, there should be a + global variable declaration to capture the result. For example, in a compiler, + we would like to support the unix standard '-o <filename>' option + to specify where to put the output. With the CommandLine library, this is + represented like this:

        + + +
        + cl::opt<string> OutputFilename("o", cl::desc("Specify output filename"), cl::value_desc("filename"));
        + 
        + +

        This declares a global variable "OutputFilename" that is used to + capture the result of the "o" argument (first parameter). We specify + that this is a simple scalar option by using the "cl::opt" template (as opposed to the "cl::list template), and tell the CommandLine library + that the data type that we are parsing is a string.

        + +

        The second and third parameters (which are optional) are used to specify what + to output for the "--help" option. In this case, we get a line that + looks like this:

        + +
        + USAGE: compiler [options]
        + 
        + OPTIONS:
        +   -help             - display available options (--help-hidden for more)
        +   -o <filename>     - Specify output filename
        + 
        + +

        Because we specified that the command line option should parse using the + string data type, the variable declared is automatically usable as a + real string in all contexts that a normal C++ string object may be used. For + example:

        + +
        +   ...
        +   ofstream Output(OutputFilename.c_str());
        +   if (Out.good()) ...
        +   ...
        + 
        + +

        There are many different options that you can use to customize the command + line option handling library, but the above example shows the general interface + to these options. The options can be specified in any order, and are specified + with helper functions like cl::desc(...), so + there are no positional dependencies to remember. The available options are + discussed in detail in the Reference Guide.

        + +

        Continuing the example, we would like to have our compiler take an input + filename as well as an output filename, but we do not want the input filename to + be specified with a hyphen (ie, not -filename.c). To support this + style of argument, the CommandLine library allows for positional arguments to be specified for the program. + These positional arguments are filled with command line parameters that are not + in option form. We use this feature like this:

        + +
        + cl::opt<string> InputFilename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
        + 
        + +

        This declaration indicates that the first positional argument should be + treated as the input filename. Here we use the cl::init option to specify an initial value for the + command line option, which is used if the option is not specified (if you do not + specify a cl::init modifier for an option, then + the default constructor for the data type is used to initialize the value). + Command line options default to being optional, so if we would like to require + that the user always specify an input filename, we would add the cl::Required flag, and we could eliminate the + cl::init modifier, like this:

        + +
        + cl::opt<string> InputFilename(cl::Positional, cl::desc("<input file>"), cl::Required);
        + 
        + +

        Again, the CommandLine library does not require the options to be specified + in any particular order, so the above declaration is equivalent to:

        + +
        + cl::opt<string> InputFilename(cl::Positional, cl::Required, cl::desc("<input file>"));
        + 
        + +

        By simply adding the cl::Required flag, + the CommandLine library will automatically issue an error if the argument is not + specified, which shifts all of the command line option verification code out of + your application into the library. This is just one example of how using flags + can alter the default behaviour of the library, on a per-option basis. By + adding one of the declarations above, the --help option synopsis is now + extended to:

        + +
        + USAGE: compiler [options] <input file>
        + 
        + OPTIONS:
        +   -help             - display available options (--help-hidden for more)
        +   -o <filename>     - Specify output filename
        + 
        + +

        ... indicating that an input filename is expected.

        + +
        + + + + +
        + +

        In addition to input and output filenames, we would like the compiler example + to support three boolean flags: "-f" to force overwriting of the output + file, "--quiet" to enable quiet mode, and "-q" for backwards + compatibility with some of our users. We can support these by declaring options + of boolean type like this:

        + +
        + cl::opt<bool> Force ("f", cl::desc("Overwrite output files"));
        + cl::opt<bool> Quiet ("quiet", cl::desc("Don't print informational messages"));
        + cl::opt<bool> Quiet2("q", cl::desc("Don't print informational messages"), cl::Hidden);
        + 
        + +

        This does what you would expect: it declares three boolean variables + ("Force", "Quiet", and "Quiet2") to recognize these + options. Note that the "-q" option is specified with the "cl::Hidden" flag. This modifier prevents it + from being shown by the standard "--help" output (note that it is still + shown in the "--help-hidden" output).

        + +

        The CommandLine library uses a different parser + for different data types. For example, in the string case, the argument passed + to the option is copied literally into the content of the string variable... we + obviously cannot do that in the boolean case, however, so we must use a smarter + parser. In the case of the boolean parser, it allows no options (in which case + it assigns the value of true to the variable), or it allows the values + "true" or "false" to be specified, allowing any of the + following inputs:

        + +
        +  compiler -f          # No value, 'Force' == true
        +  compiler -f=true     # Value specified, 'Force' == true
        +  compiler -f=TRUE     # Value specified, 'Force' == true
        +  compiler -f=FALSE    # Value specified, 'Force' == false
        + 
        + +

        ... you get the idea. The bool parser just turns + the string values into boolean values, and rejects things like 'compiler + -f=foo'. Similarly, the float, double, and int parsers work + like you would expect, using the 'strtol' and 'strtod' C + library calls to parse the string value into the specified data type.

        + +

        With the declarations above, "compiler --help" emits this:

        + +
        + USAGE: compiler [options] <input file>
        + 
        + OPTIONS:
        +   -f     - Overwrite output files
        +   -o     - Override output filename
        +   -quiet - Don't print informational messages
        +   -help  - display available options (--help-hidden for more)
        + 
        + +

        and "opt --help-hidden" prints this:

        + +
        + USAGE: compiler [options] <input file>
        + 
        + OPTIONS:
        +   -f     - Overwrite output files
        +   -o     - Override output filename
        +   -q     - Don't print informational messages
        +   -quiet - Don't print informational messages
        +   -help  - display available options (--help-hidden for more)
        + 
        + +

        This brief example has shown you how to use the 'cl::opt' class to parse simple scalar command line + arguments. In addition to simple scalar arguments, the CommandLine library also + provides primitives to support CommandLine option aliases, + and lists of options.

        + +
        + + + + +
        + +

        So far, the example works well, except for the fact that we need to check the + quiet condition like this now:

        + +
        + ...
        +   if (!Quiet && !Quiet2) printInformationalMessage(...);
        + ...
        + 
        + +

        ... which is a real pain! Instead of defining two values for the same + condition, we can use the "cl::alias" class to make the "-q" + option an alias for the "-quiet" option, instead of providing + a value itself:

        + +
        + cl::opt<bool> Force ("f", cl::desc("Overwrite output files"));
        + cl::opt<bool> Quiet ("quiet", cl::desc("Don't print informational messages"));
        + cl::alias     QuietA("q", cl::desc("Alias for -quiet"), cl::aliasopt(Quiet));
        + 
        + +

        The third line (which is the only one we modified from above) defines a + "-q alias that updates the "Quiet" variable (as specified by + the cl::aliasopt modifier) whenever it is + specified. Because aliases do not hold state, the only thing the program has to + query is the Quiet variable now. Another nice feature of aliases is + that they automatically hide themselves from the -help output + (although, again, they are still visible in the --help-hidden + output).

        + +

        Now the application code can simply use:

        + +
        + ...
        +   if (!Quiet) printInformationalMessage(...);
        + ...
        + 
        + +

        ... which is much nicer! The "cl::alias" + can be used to specify an alternative name for any variable type, and has many + uses.

        + +
        + + + + +
        + +

        So far, we have seen how the CommandLine library handles builtin types like + std::string, bool and int, but how does it handle + things it doesn't know about, like enums or 'int*'s?

        + +

        The answer is that it uses a table driven generic parser (unless you specify + your own parser, as described in the Extension + Guide). This parser maps literal strings to whatever type is required, are + requires you to tell it what this mapping should be.

        + +

        Lets say that we would like to add four optimizations levels to our + optimizer, using the standard flags "-g", "-O0", + "-O1", and "-O2". We could easily implement this with boolean + options like above, but there are several problems with this strategy:

        + +
          +
        1. A user could specify more than one of the options at a time, for example, + "opt -O3 -O2". The CommandLine library would not be able to catch this + erroneous input for us.
        2. + +
        3. We would have to test 4 different variables to see which ones are set.
        4. + +
        5. This doesn't map to the numeric levels that we want... so we cannot easily + see if some level >= "-O1" is enabled.
        6. + +
        + +

        To cope with these problems, we can use an enum value, and have the + CommandLine library fill it in with the appropriate level directly, which is + used like this:

        + +
        + enum OptLevel {
        +   g, O1, O2, O3
        + };
        + 
        + cl::opt<OptLevel> OptimizationLevel(cl::desc("Choose optimization level:"),
        +   cl::values(
        +     clEnumVal(g , "No optimizations, enable debugging"),
        +     clEnumVal(O1, "Enable trivial optimizations"),
        +     clEnumVal(O2, "Enable default optimizations"),
        +     clEnumVal(O3, "Enable expensive optimizations"),
        +    clEnumValEnd));
        + 
        + ...
        +   if (OptimizationLevel >= O2) doPartialRedundancyElimination(...);
        + ...
        + 
        + +

        This declaration defines a variable "OptimizationLevel" of the + "OptLevel" enum type. This variable can be assigned any of the values + that are listed in the declaration (Note that the declaration list must be + terminated with the "clEnumValEnd" argument!). The CommandLine + library enforces + that the user can only specify one of the options, and it ensure that only valid + enum values can be specified. The "clEnumVal" macros ensure that the + command line arguments matched the enum values. With this option added, our + help output now is:

        + +
        + USAGE: compiler [options] <input file>
        + 
        + OPTIONS:
        +   Choose optimization level:
        +     -g          - No optimizations, enable debugging
        +     -O1         - Enable trivial optimizations
        +     -O2         - Enable default optimizations
        +     -O3         - Enable expensive optimizations
        +   -f            - Overwrite output files
        +   -help         - display available options (--help-hidden for more)
        +   -o <filename> - Specify output filename
        +   -quiet        - Don't print informational messages
        + 
        + +

        In this case, it is sort of awkward that flag names correspond directly to + enum names, because we probably don't want a enum definition named "g" + in our program. Because of this, we can alternatively write this example like + this:

        + +
        + enum OptLevel {
        +   Debug, O1, O2, O3
        + };
        + 
        + cl::opt<OptLevel> OptimizationLevel(cl::desc("Choose optimization level:"),
        +   cl::values(
        +    clEnumValN(Debug, "g", "No optimizations, enable debugging"),
        +     clEnumVal(O1        , "Enable trivial optimizations"),
        +     clEnumVal(O2        , "Enable default optimizations"),
        +     clEnumVal(O3        , "Enable expensive optimizations"),
        +    clEnumValEnd));
        + 
        + ...
        +   if (OptimizationLevel == Debug) outputDebugInfo(...);
        + ...
        + 
        + +

        By using the "clEnumValN" macro instead of "clEnumVal", we + can directly specify the name that the flag should get. In general a direct + mapping is nice, but sometimes you can't or don't want to preserve the mapping, + which is when you would use it.

        + +
        + + + + +
        + +

        Another useful argument form is a named alternative style. We shall use this + style in our compiler to specify different debug levels that can be used. + Instead of each debug level being its own switch, we want to support the + following options, of which only one can be specified at a time: + "--debug-level=none", "--debug-level=quick", + "--debug-level=detailed". To do this, we use the exact same format as + our optimization level flags, but we also specify an option name. For this + case, the code looks like this:

        + +
        + enum DebugLev {
        +   nodebuginfo, quick, detailed
        + };
        + 
        + // Enable Debug Options to be specified on the command line
        + cl::opt<DebugLev> DebugLevel("debug_level", cl::desc("Set the debugging level:"),
        +   cl::values(
        +     clEnumValN(nodebuginfo, "none", "disable debug information"),
        +      clEnumVal(quick,               "enable quick debug information"),
        +      clEnumVal(detailed,            "enable detailed debug information"),
        +     clEnumValEnd));
        + 
        + +

        This definition defines an enumerated command line variable of type "enum + DebugLev", which works exactly the same way as before. The difference here + is just the interface exposed to the user of your program and the help output by + the "--help" option:

        + +
        + USAGE: compiler [options] <input file>
        + 
        + OPTIONS:
        +   Choose optimization level:
        +     -g          - No optimizations, enable debugging
        +     -O1         - Enable trivial optimizations
        +     -O2         - Enable default optimizations
        +     -O3         - Enable expensive optimizations
        +   -debug_level  - Set the debugging level:
        +     =none       - disable debug information
        +     =quick      - enable quick debug information
        +     =detailed   - enable detailed debug information
        +   -f            - Overwrite output files
        +   -help         - display available options (--help-hidden for more)
        +   -o <filename> - Specify output filename
        +   -quiet        - Don't print informational messages
        + 
        + +

        Again, the only structural difference between the debug level declaration and + the optimiation level declaration is that the debug level declaration includes + an option name ("debug_level"), which automatically changes how the + library processes the argument. The CommandLine library supports both forms so + that you can choose the form most appropriate for your application.

        + +
        + + + + +
        + +

        Now that we have the standard run of the mill argument types out of the way, + lets get a little wild and crazy. Lets say that we want our optimizer to accept + a list of optimizations to perform, allowing duplicates. For example, we + might want to run: "compiler -dce -constprop -inline -dce -strip". In + this case, the order of the arguments and the number of appearances is very + important. This is what the "cl::list" + template is for. First, start by defining an enum of the optimizations that you + would like to perform:

        + +
        + enum Opts {
        +   // 'inline' is a C++ keyword, so name it 'inlining'
        +   dce, constprop, inlining, strip
        + };
        + 
        + +

        Then define your "cl::list" variable:

        + +
        + cl::list<Opts> OptimizationList(cl::desc("Available Optimizations:"),
        +   cl::values(
        +     clEnumVal(dce               , "Dead Code Elimination"),
        +     clEnumVal(constprop         , "Constant Propagation"),
        +    clEnumValN(inlining, "inline", "Procedure Integration"),
        +     clEnumVal(strip             , "Strip Symbols"),
        +   clEnumValEnd));
        + 
        + +

        This defines a variable that is conceptually of the type + "std::vector<enum Opts>". Thus, you can access it with standard + vector methods:

        + +
        +   for (unsigned i = 0; i != OptimizationList.size(); ++i)
        +     switch (OptimizationList[i])
        +        ...
        + 
        + +

        ... to iterate through the list of options specified.

        + +

        Note that the "cl::list" template is + completely general and may be used with any data types or other arguments that + you can use with the "cl::opt" template. One + especially useful way to use a list is to capture all of the positional + arguments together if there may be more than one specified. In the case of a + linker, for example, the linker takes several '.o' files, and needs to + capture them into a list. This is naturally specified as:

        + +
        + ...
        + cl::list<std::string> InputFilenames(cl::Positional, cl::desc("<Input files>"), cl::OneOrMore);
        + ...
        + 
        + +

        This variable works just like a "vector<string>" object. As + such, accessing the list is simple, just like above. In this example, we used + the cl::OneOrMore modifier to inform the + CommandLine library that it is an error if the user does not specify any + .o files on our command line. Again, this just reduces the amount of + checking we have to do.

        + +
        + + + + +
        + +

        As our program grows and becomes more mature, we may decide to put summary + information about what it does into the help output. The help output is styled + to look similar to a Unix man page, providing concise information about + a program. Unix man pages, however often have a description about what + the program does. To add this to your CommandLine program, simply pass a third + argument to the cl::ParseCommandLineOptions + call in main. This additional argument is then printed as the overview + information for your program, allowing you to include any additional information + that you want. For example:

        + +
        + int main(int argc, char **argv) {
        +   cl::ParseCommandLineOptions(argc, argv, " CommandLine compiler example\n\n"
        +                               "  This program blah blah blah...\n");
        +   ...
        + }
        + 
        + +

        Would yield the help output:

        + +
        + OVERVIEW: CommandLine compiler example
        + 
        +   This program blah blah blah...
        + 
        + USAGE: compiler [options] <input file>
        + 
        + OPTIONS:
        +   ...
        +   -help             - display available options (--help-hidden for more)
        +   -o <filename>     - Specify output filename
        + 
        + +
        + + + + + + +
        + +

        Now that you know the basics of how to use the CommandLine library, this + section will give you the detailed information you need to tune how command line + options work, as well as information on more "advanced" command line option + processing capabilities.

        + +
        + + + + +
        + +

        Positional arguments are those arguments that are not named, and are not + specified with a hyphen. Positional arguments should be used when an option is + specified by its position alone. For example, the standard Unix grep + tool takes a regular expression argument, and an optional filename to search + through (which defaults to standard input if a filename is not specified). + Using the CommandLine library, this would be specified as:

        + +
        + cl::opt<string> Regex   (cl::Positional, cl::desc("<regular expression>"), cl::Required);
        + cl::opt<string> Filename(cl::Positional, cl::desc("<input file>"), cl::init("-"));
        + 
        + +

        Given these two option declarations, the --help output for our grep + replacement would look like this:

        + +
        + USAGE: spiffygrep [options] <regular expression> <input file>
        + 
        + OPTIONS:
        +   -help - display available options (--help-hidden for more)
        + 
        + +

        ... and the resultant program could be used just like the standard + grep tool.

        + +

        Positional arguments are sorted by their order of construction. This means + that command line options will be ordered according to how they are listed in a + .cpp file, but will not have an ordering defined if they positional arguments + are defined in multiple .cpp files. The fix for this problem is simply to + define all of your positional arguments in one .cpp file.

        + +
        + + + + + +
        + +

        Sometimes you may want to specify a value to your positional argument that + starts with a hyphen (for example, searching for '-foo' in a file). At + first, you will have trouble doing this, because it will try to find an argument + named '-foo', and will fail (and single quotes will not save you). + Note that the system grep has the same problem:

        + +
        +   $ spiffygrep '-foo' test.txt
        +   Unknown command line argument '-foo'.  Try: spiffygrep --help'
        + 
        +   $ grep '-foo' test.txt
        +   grep: illegal option -- f
        +   grep: illegal option -- o
        +   grep: illegal option -- o
        +   Usage: grep -hblcnsviw pattern file . . .
        + 
        + +

        The solution for this problem is the same for both your tool and the system + version: use the '--' marker. When the user specifies '--' on + the command line, it is telling the program that all options after the + '--' should be treated as positional arguments, not options. Thus, we + can use it like this:

        + +
        +   $ spiffygrep -- -foo test.txt
        +     ...output...
        + 
        + +
        + + + + +
        + +

        The cl::ConsumeAfter formatting option is + used to construct programs that use "interpreter style" option processing. With + this style of option processing, all arguments specified after the last + positional argument are treated as special interpreter arguments that are not + interpreted by the command line argument.

        + +

        As a concrete example, lets say we are developing a replacement for the + standard Unix Bourne shell (/bin/sh). To run /bin/sh, first + you specify options to the shell itself (like -x which turns on trace + output), then you specify the name of the script to run, then you specify + arguments to the script. These arguments to the script are parsed by the bourne + shell command line option processor, but are not interpreted as options to the + shell itself. Using the CommandLine library, we would specify this as:

        + +
        + cl::opt<string> Script(cl::Positional, cl::desc("<input script>"), cl::init("-"));
        + cl::list<string>  Argv(cl::ConsumeAfter, cl::desc("<program arguments>..."));
        + cl::opt<bool>    Trace("x", cl::desc("Enable trace output"));
        + 
        + +

        which automatically provides the help output:

        + +
        + USAGE: spiffysh [options] <input script> <program arguments>...
        + 
        + OPTIONS:
        +   -help - display available options (--help-hidden for more)
        +   -x    - Enable trace output
        + 
        + +

        At runtime, if we run our new shell replacement as 'spiffysh -x test.sh + -a -x -y bar', the Trace variable will be set to true, the + Script variable will be set to "test.sh", and the + Argv list will contain ["-a", "-x", "-y", "bar"], because they + were specified after the last positional argument (which is the script + name).

        + +

        There are several limitations to when cl::ConsumeAfter options can + be specified. For example, only one cl::ConsumeAfter can be specified + per program, there must be at least one positional + argument specified, there must not be any cl::list + positional arguments, and the cl::ConsumeAfter option should be a cl::list option.

        + +
        + + + + +
        + +

        By default, all command line options automatically hold the value that they + parse from the command line. This is very convenient in the common case, + especially when combined with the ability to define command line options in the + files that use them. This is called the internal storage model.

        + +

        Sometimes, however, it is nice to separate the command line option processing + code from the storage of the value parsed. For example, lets say that we have a + '-debug' option that we would like to use to enable debug information + across the entire body of our program. In this case, the boolean value + controlling the debug code should be globally accessable (in a header file, for + example) yet the command line option processing code should not be exposed to + all of these clients (requiring lots of .cpp files to #include + CommandLine.h).

        + +

        To do this, set up your .h file with your option, like this for example:

        + +
        + // DebugFlag.h - Get access to the '-debug' command line option
        + //
        + 
        + // DebugFlag - This boolean is set to true if the '-debug' command line option
        + // is specified.  This should probably not be referenced directly, instead, use
        + // the DEBUG macro below.
        + //
        + extern bool DebugFlag;
        + 
        + // DEBUG macro - This macro should be used by code to emit debug information.
        + // In the '-debug' option is specified on the command line, and if this is a
        + // debug build, then the code specified as the option to the macro will be
        + // executed.  Otherwise it will not be.  Example:
        + //
        + // DEBUG(cerr << "Bitset contains: " << Bitset << "\n");
        + //
        + #ifdef NDEBUG
        + #define DEBUG(X)
        + #else
        + #define DEBUG(X) \
        +   do { if (DebugFlag) { X; } } while (0)
        + #endif
        + 
        + +

        This allows clients to blissfully use the DEBUG() macro, or the + DebugFlag explicitly if they want to. Now we just need to be able to + set the DebugFlag boolean when the option is set. To do this, we pass + an additial argument to our command line argument processor, and we specify + where to fill in with the cl::location + attribute:

        + +
        + bool DebugFlag;      // the actual value
        + static cl::opt<bool, true>       // The parser
        + Debug("debug", cl::desc("Enable debug output"), cl::Hidden,
        +       cl::location(DebugFlag));
        + 
        + +

        In the above example, we specify "true" as the second argument to + the cl::opt template, indicating that the template should + not maintain a copy of the value itself. In addition to this, we specify the cl::location attribute, so that DebugFlag is + automatically set.

        + +
        + + + + +
        + +

        This section describes the basic attributes that you can specify on + options.

        + +
          + +
        • The option name attribute (which is required for all options, except positional options) specifies what the option name is. + This option is specified in simple double quotes: + +
          + cl::opt<bool> Quiet("quiet");
          + 
          + +
        • + +
        • The cl::desc attribute specifies a + description for the option to be shown in the --help output for the + program.
        • + +
        • The cl::value_desc attribute + specifies a string that can be used to fine tune the --help output for + a command line option. Look here for an + example.
        • + +
        • The cl::init attribute specifies an + inital value for a scalar option. If this attribute is + not specified then the command line option value defaults to the value created + by the default constructor for the type. Warning: If you specify both + cl::init and cl::location for an option, + you must specify cl::location first, so that when the + command-line parser sees cl::init, it knows where to put the + initial value. (You will get an error at runtime if you don't put them in + the right order.)
        • + +
        • The cl::location attribute where to + store the value for a parsed command line option if using external storage. See + the section on Internal vs External Storage for more + information.
        • + +
        • The cl::aliasopt attribute + specifies which option a cl::alias option is an alias + for.
        • + +
        • The cl::values attribute specifies + the string-to-value mapping to be used by the generic parser. It takes a + clEnumValEnd terminated list of (option, value, description) triplets + that + specify the option name, the value mapped to, and the description shown in the + --help for the tool. Because the generic parser is used most + frequently with enum values, two macros are often useful: + +
            + +
          1. The clEnumVal macro is used as a + nice simple way to specify a triplet for an enum. This macro automatically + makes the option name be the same as the enum name. The first option to the + macro is the enum, the second is the description for the command line + option.
          2. + +
          3. The clEnumValN macro is used to + specify macro options where the option name doesn't equal the enum name. For + this macro, the first argument is the enum value, the second is the flag name, + and the second is the description.
          4. + +
          + + You will get a compile time error if you try to use cl::values with a parser + that does not support it.
        • + +
        + +
        + + + + +
        + +

        Option modifiers are the flags and expressions that you pass into the + constructors for cl::opt and cl::list. These modifiers give you the ability to + tweak how options are parsed and how --help output is generated to fit + your application well.

        + +

        These options fall into five main catagories:

        + +
          +
        1. Hiding an option from --help output
        2. +
        3. Controlling the number of occurrences + required and allowed
        4. +
        5. Controlling whether or not a value must be + specified
        6. +
        7. Controlling other formatting options
        8. +
        9. Miscellaneous option modifiers
        10. +
        + +

        It is not possible to specify two options from the same catagory (you'll get + a runtime error) to a single option, except for options in the miscellaneous + catagory. The CommandLine library specifies defaults for all of these settings + that are the most useful in practice and the most common, which mean that you + usually shouldn't have to worry about these.

        + +
        + + + + +
        + +

        The cl::NotHidden, cl::Hidden, and + cl::ReallyHidden modifiers are used to control whether or not an option + appears in the --help and --help-hidden output for the + compiled program:

        + +
          + +
        • The cl::NotHidden modifier + (which is the default for cl::opt and cl::list options), indicates the option is to appear + in both help listings.
        • + +
        • The cl::Hidden modifier (which is the + default for cl::alias options), indicates that + the option should not appear in the --help output, but should appear in + the --help-hidden output.
        • + +
        • The cl::ReallyHidden modifier, + indicates that the option should not appear in any help output.
        • + +
        + +
        + + + + +
        + +

        This group of options is used to control how many time an option is allowed + (or required) to be specified on the command line of your program. Specifying a + value for this setting allows the CommandLine library to do error checking for + you.

        + +

        The allowed values for this option group are:

        + +
          + +
        • The cl::Optional modifier (which + is the default for the cl::opt and cl::alias classes) indicates that your program will + allow either zero or one occurrence of the option to be specified.
        • + +
        • The cl::ZeroOrMore modifier + (which is the default for the cl::list class) + indicates that your program will allow the option to be specified zero or more + times.
        • + +
        • The cl::Required modifier + indicates that the specified option must be specified exactly one time.
        • + +
        • The cl::OneOrMore modifier + indicates that the option must be specified at least one time.
        • + +
        • The cl::ConsumeAfter modifier is described in the Positional arguments section
        • + +
        + +

        If an option is not specified, then the value of the option is equal to the + value specified by the cl::init attribute. If + the cl::init attribute is not specified, the + option value is initialized with the default constructor for the data type.

        + +

        If an option is specified multiple times for an option of the cl::opt class, only the last value will be + retained.

        + +
        + + + + +
        + +

        This group of options is used to control whether or not the option allows a + value to be present. In the case of the CommandLine library, a value is either + specified with an equal sign (e.g. '-index-depth=17') or as a trailing + string (e.g. '-o a.out').

        + +

        The allowed values for this option group are:

        + +
          + +
        • The cl::ValueOptional modifier + (which is the default for bool typed options) specifies that it is + acceptable to have a value, or not. A boolean argument can be enabled just by + appearing on the command line, or it can have an explicit '-foo=true'. + If an option is specified with this mode, it is illegal for the value to be + provided without the equal sign. Therefore '-foo true' is illegal. To + get this behavior, you must use the cl::ValueRequired modifier.
        • + +
        • The cl::ValueRequired modifier + (which is the default for all other types except for unnamed alternatives using the generic parser) + specifies that a value must be provided. This mode informs the command line + library that if an option is not provides with an equal sign, that the next + argument provided must be the value. This allows things like '-o + a.out' to work.
        • + +
        • The cl::ValueDisallowed + modifier (which is the default for unnamed + alternatives using the generic parser) indicates that it is a runtime error + for the user to specify a value. This can be provided to disallow users from + providing options to boolean options (like '-foo=true').
        • + +
        + +

        In general, the default values for this option group work just like you would + want them to. As mentioned above, you can specify the cl::ValueDisallowed modifier to a boolean + argument to restrict your command line parser. These options are mostly useful + when extending the library.

        + +
        + + + + +
        + +

        The formatting option group is used to specify that the command line option + has special abilities and is otherwise different from other command line + arguments. As usual, you can only specify at most one of these arguments.

        + +
          + +
        • The cl::NormalFormatting + modifier (which is the default all options) specifies that this option is + "normal".
        • + +
        • The cl::Positional modifier + specifies that this is a positional argument, that does not have a command line + option associated with it. See the Positional + Arguments section for more information.
        • + +
        • The cl::ConsumeAfter modifier + specifies that this option is used to capture "interpreter style" arguments. See this section for more information.
        • + +
        • The cl::Prefix modifier specifies + that this option prefixes its value. With 'Prefix' options, there is no equal + sign that separates the value from the option name specified. This is useful + for processing odd arguments like '-lmalloc -L/usr/lib' in a linker + tool. Here, the 'l' and 'L' options are normal string (list) + options, that have the cl::Prefix modifier added to + allow the CommandLine library to recognize them. Note that cl::Prefix options must not have the cl::ValueDisallowed modifier specified.
        • + +
        • The cl::Grouping modifier is used + to implement unix style tools (like ls) that have lots of single letter + arguments, but only require a single dash. For example, the 'ls -labF' + command actually enables four different options, all of which are single + letters. Note that cl::Grouping options cannot have + values.
        • + +
        + +

        The CommandLine library does not restrict how you use the cl::Prefix or cl::Grouping + modifiers, but it is possible to specify ambiguous argument settings. Thus, it + is possible to have multiple letter options that are prefix or grouping options, + and they will still work as designed.

        + +

        To do this, the CommandLine library uses a greedy algorithm to parse the + input option into (potentially multiple) prefix and grouping options. The + strategy basically looks like this:

        + +

        parse(string OrigInput) { + +

          +
        1. string input = OrigInput; +
        2. if (isOption(input)) return getOption(input).parse();    // Normal option +
        3. while (!isOption(input) && !input.empty()) input.pop_back();    // Remove the last letter +
        4. if (input.empty()) return error();    // No matching option +
        5. if (getOption(input).isPrefix())
          +   return getOption(input).parse(input);
          +
        6. while (!input.empty()) {    // Must be grouping options
          +   getOption(input).parse();
          +   OrigInput.erase(OrigInput.begin(), OrigInput.begin()+input.length());
          +   input = OrigInput;
          +   while (!isOption(input) && !input.empty()) input.pop_back();
          + }
          +
        7. if (!OrigInput.empty()) error();
        8. + +
        + +

        }

        + +
        + + + + +
        + +

        The miscellaneous option modifiers are the only flags where you can specify + more than one flag from the set: they are not mutually exclusive. These flags + specify boolean properties that modify the option.

        + +
          + +
        • The cl::CommaSeparated modifier + indicates that any commas specified for an option's value should be used to + split the value up into multiple values for the option. For example, these two + options are equivalent when cl::CommaSeparated is specified: + "-foo=a -foo=b -foo=c" and "-foo=a,b,c". This option only + makes sense to be used in a case where the option is allowed to accept one or + more values (i.e. it is a cl::list option).
        • + +
        • The + cl::PositionalEatsArgs modifier (which only applies to + positional arguments, and only makes sense for lists) indicates that positional + argument should consume any strings after it (including strings that start with + a "-") up until another recognized positional argument. For example, if you + have two "eating" positional arguments "pos1" and "pos2" the + string "-pos1 -foo -bar baz -pos2 -bork" would cause the "-foo -bar + -baz" strings to be applied to the "-pos1" option and the + "-bork" string to be applied to the "-pos2" option.
        • + +
        + +

        So far, these are the only two miscellaneous option modifiers.

        + +
        + + + + +
        + +

        Despite all of the built-in flexibility, the CommandLine option library + really only consists of one function (cl::ParseCommandLineOptions) + and three main classes: cl::opt, cl::list, and cl::alias. This section describes these three + classes in detail.

        + +
        + + + + +
        + +

        The cl::ParseCommandLineOptions function is designed to be called + directly from main, and is used to fill in the values of all of the + command line option variables once argc and argv are + available.

        + +

        The cl::ParseCommandLineOptions function requires two parameters + (argc and argv), but may also take an optional third parameter + which holds additional extra text to emit when the + --help option is invoked.

        + +
        + + + + +
        + +

        The cl::ParseEnvironmentOptions function has mostly the same effects + as cl::ParseCommandLineOptions, + except that it is designed to take values for options from an environment + variable, for those cases in which reading the command line is not convenient or + not desired. It fills in the values of all the command line option variables + just like cl::ParseCommandLineOptions + does.

        + +

        It takes three parameters: first, the name of the program (since + argv may not be available, it can't just look in argv[0]), + second, the name of the environment variable to examine, and third, the optional + additional extra text to emit when the + --help option is invoked.

        + +

        cl::ParseEnvironmentOptions will break the environment + variable's value up into words and then process them using + cl::ParseCommandLineOptions. + Note: Currently cl::ParseEnvironmentOptions does not support + quoting, so an environment variable containing -option "foo bar" will + be parsed as three words, -option, "foo, and bar", + which is different from what you would get from the shell with the same + input.

        + +
        + + + + +
        + +

        The cl::opt class is the class used to represent scalar command line + options, and is the one used most of the time. It is a templated class which + can take up to three arguments (all except for the first have default values + though):

        + +
        + namespace cl {
        +   template <class DataType, bool ExternalStorage = false,
        +             class ParserClass = parser<DataType> >
        +   class opt;
        + }
        + 
        + +

        The first template argument specifies what underlying data type the command + line argument is, and is used to select a default parser implementation. The + second template argument is used to specify whether the option should contain + the storage for the option (the default) or whether external storage should be + used to contain the value parsed for the option (see Internal + vs External Storage for more information).

        + +

        The third template argument specifies which parser to use. The default value + selects an instantiation of the parser class based on the underlying + data type of the option. In general, this default works well for most + applications, so this option is only used when using a custom parser.

        + +
        + + + + +
        + +

        The cl::list class is the class used to represent a list of command + line options. It too is a templated class which can take up to three + arguments:

        + +
        + namespace cl {
        +   template <class DataType, class Storage = bool,
        +             class ParserClass = parser<DataType> >
        +   class list;
        + }
        + 
        + +

        This class works the exact same as the cl::opt class, except that the second argument is + the type of the external storage, not a boolean value. For this class, + the marker type 'bool' is used to indicate that internal storage should + be used.

        + +
        + + + + +
        + +

        The cl::alias class is a nontemplated class that is used to form + aliases for other arguments.

        + +
        + namespace cl {
        +   class alias;
        + }
        + 
        + +

        The cl::aliasopt attribute should be + used to specify which option this is an alias for. Alias arguments default to + being Hidden, and use the aliased options parser to do + the conversion from string to data.

        + +
        + + + + +
        + +

        Parsers control how the string value taken from the command line is + translated into a typed value, suitable for use in a C++ program. By default, + the CommandLine library uses an instance of parser<type> if the + command line option specifies that it uses values of type 'type'. + Because of this, custom option processing is specified with specializations of + the 'parser' class.

        + +

        The CommandLine library provides the following builtin parser + specializations, which are sufficient for most applications. It can, however, + also be extended to work with new data types and new ways of interpreting the + same data. See the Writing a Custom Parser for more + details on this type of library extension.

        + +
          + +
        • The generic parser<t> parser + can be used to map strings values to any data type, through the use of the cl::values property, which specifies the mapping + information. The most common use of this parser is for parsing enum values, + which allows you to use the CommandLine library for all of the error checking to + make sure that only valid enum values are specified (as opposed to accepting + arbitrary strings). Despite this, however, the generic parser class can be used + for any data type.
        • + +
        • The parser<bool> specialization + is used to convert boolean strings to a boolean value. Currently accepted + strings are "true", "TRUE", "True", "1", + "false", "FALSE", "False", and "0".
        • + +
        • The parser<string> + specialization simply stores the parsed string into the string value + specified. No conversion or modification of the data is performed.
        • + +
        • The parser<int> specialization + uses the C strtol function to parse the string input. As such, it will + accept a decimal number (with an optional '+' or '-' prefix) which must start + with a non-zero digit. It accepts octal numbers, which are identified with a + '0' prefix digit, and hexadecimal numbers with a prefix of + '0x' or '0X'.
        • + +
        • The parser<double> and + parser<float> specializations use the standard C + strtod function to convert floating point strings into floating point + values. As such, a broad range of string formats is supported, including + exponential notation (ex: 1.7e15) and properly supports locales. +
        • + +
        + +
        + + + + + +
        + +

        Although the CommandLine library has a lot of functionality built into it + already (as discussed previously), one of its true strengths lie in its + extensibility. This section discusses how the CommandLine library works under + the covers and illustrates how to do some simple, common, extensions.

        + +
        + + + + +
        + +

        One of the simplest and most common extensions is the use of a custom parser. + As discussed previously, parsers are the portion + of the CommandLine library that turns string input from the user into a + particular parsed data type, validating the input in the process.

        + +

        There are two ways to use a new parser:

        + +
          + +
        1. + +

          Specialize the cl::parser template for + your custom data type.

          + +

          This approach has the advantage that users of your custom data type will + automatically use your custom parser whenever they define an option with a value + type of your data type. The disadvantage of this approach is that it doesn't + work if your fundemental data type is something that is already supported.

          + +
        2. + +
        3. + +

          Write an independent class, using it explicitly from options that need + it.

          + +

          This approach works well in situations where you would line to parse an + option using special syntax for a not-very-special data-type. The drawback of + this approach is that users of your parser have to be aware that they are using + your parser, instead of the builtin ones.

          + +
        4. + +
        + +

        To guide the discussion, we will discuss a custom parser that accepts file + sizes, specified with an optional unit after the numeric size. For example, we + would like to parse "102kb", "41M", "1G" into the appropriate integer value. In + this case, the underlying data type we want to parse into is + 'unsigned'. We choose approach #2 above because we don't want to make + this the default for all unsigned options.

        + +

        To start out, we declare our new FileSizeParser class:

        + +
        + struct FileSizeParser : public cl::basic_parser<unsigned> {
        +   // parse - Return true on error.
        +   bool parse(cl::Option &O, const char *ArgName, const std::string &ArgValue,
        +              unsigned &Val);
        + };
        + 
        + +

        Our new class inherits from the cl::basic_parser template class to + fill in the default, boiler plate, code for us. We give it the data type that + we parse into (the last argument to the parse method so that clients of + our custom parser know what object type to pass in to the parse method (here we + declare that we parse into 'unsigned' variables.

        + +

        For most purposes, the only method that must be implemented in a custom + parser is the parse method. The parse method is called + whenever the option is invoked, passing in the option itself, the option name, + the string to parse, and a reference to a return value. If the string to parse + is not well formed, the parser should output an error message and return true. + Otherwise it should return false and set 'Val' to the parsed value. In + our example, we implement parse as:

        + +
        + bool FileSizeParser::parse(cl::Option &O, const char *ArgName,
        +                            const std::string &Arg, unsigned &Val) {
        +   const char *ArgStart = Arg.c_str();
        +   char *End;
        +  
        +   // Parse integer part, leaving 'End' pointing to the first non-integer char
        +   Val = (unsigned)strtol(ArgStart, &End, 0);
        + 
        +   while (1) {
        +     switch (*End++) {
        +     case 0: return false;   // No error
        +     case 'i':               // Ignore the 'i' in KiB if people use that
        +     case 'b': case 'B':     // Ignore B suffix
        +       break;
        + 
        +     case 'g': case 'G': Val *= 1024*1024*1024; break;
        +     case 'm': case 'M': Val *= 1024*1024;      break;
        +     case 'k': case 'K': Val *= 1024;           break;
        + 
        +     default:
        +       // Print an error message if unrecognized character!
        +       return O.error(": '" + Arg + "' value invalid for file size argument!");
        +     }
        +   }
        + }
        + 
        + +

        This function implements a very simple parser for the kinds of strings we are + interested in. Although it has some holes (it allows "123KKK" for + example), it is good enough for this example. Note that we use the option + itself to print out the error message (the error method always returns + true) in order to get a nice error message (shown below). Now that we have our + parser class, we can use it like this:

        + +
        + static cl::opt<unsigned, false, FileSizeParser>
        + MFS("max-file-size", cl::desc("Maximum file size to accept"),
        +     cl::value_desc("size"));
        + 
        + +

        Which adds this to the output of our program:

        + +
        + OPTIONS:
        +   -help                 - display available options (--help-hidden for more)
        +   ...
        +   -max-file-size=<size> - Maximum file size to accept
        + 
        + +

        And we can test that our parse works correctly now (the test program just + prints out the max-file-size argument value):

        + +
        + $ ./test
        + MFS: 0
        + $ ./test -max-file-size=123MB
        + MFS: 128974848
        + $ ./test -max-file-size=3G
        + MFS: 3221225472
        + $ ./test -max-file-size=dog
        + -max-file-size option: 'dog' value invalid for file size argument!
        + 
        + +

        It looks like it works. The error message that we get is nice and helpful, + and we seem to accept reasonable file sizes. This wraps up the "custom parser" + tutorial.

        + +
        + + + + +
        + +

        TODO: fill in this section

        + +
        + + + + +
        + +

        TODO: fill in this section

        + +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
        + LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + + + Index: llvm-www/releases/1.3/docs/ExtendingLLVM.html diff -c /dev/null llvm-www/releases/1.3/docs/ExtendingLLVM.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/ExtendingLLVM.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,238 ---- + + + + Extending LLVM: Adding instructions, intrinsics, types, etc. + + + + + +
        + Extending LLVM: Adding instructions, intrinsics, types, etc. +
        + +
          +
        1. Introduction and Warning
        2. +
        3. Adding a new intrinsic function
        4. +
        5. Adding a new instruction
        6. +
        7. Adding a new type +
            +
          1. Adding a new fundamental type
          2. +
          3. Adding a new derived type
          4. +
        8. +
        + +
        +

        Written by Misha Brukman

        +
        + + + + + +
        + +

        During the course of using LLVM, you may wish to customize it for your + research project or for experimentation. At this point, you may realize that + you need to add something to LLVM, whether it be a new fundamental type, a new + intrinsic function, or a whole new instruction.

        + +

        When you come to this realization, stop and think. Do you really need to + extend LLVM? Is it a new fundamental capability that LLVM does not support at + its current incarnation or can it be synthesized from already pre-existing LLVM + elements? If you are not sure, ask on the LLVM-dev list. The + reason is that extending LLVM will get involved as you need to update all the + different passes that you intend to use with your extension, and there are + many LLVM analyses and transformations, so it may be quite a bit of + work.

        + +

        Adding an intrinsic function is easier than adding + an instruction, and is transparent to optimization passes which treat it as an + unanalyzable function. If your added functionality can be expressed as a + function call, an intrinsic function is the method of choice for LLVM + extension.

        + +

        Before you invest a significant amount of effort into a non-trivial + extension, ask on the list if what you are + looking to do can be done with already-existing infrastructure, or if maybe + someone else is already working on it. You will save yourself a lot of time and + effort by doing so.

        + +

        Finally, these are my notes, and since my extensions are not complete, I may + be missing steps. If you find some omissions, please let me know directly or post on LLVM-dev.

        + +
        + + + + + +
        + +

        Adding a new intrinsic function to LLVM is much easier than adding a new + instruction. Almost all extensions to LLVM should start as an intrinsic + function and then be turned into an instruction if warranted.

        + +
          +
        1. llvm/docs/LangRef.html: + Document the intrinsic. Decide whether it is code generator specific and + what the restrictions are. Talk to other people about it so that you are + sure it's a good idea.
        2. + +
        3. llvm/include/llvm/Intrinsics.h: + add an enum in the llvm::Intrinsic namespace
        4. + +
        5. llvm/lib/CodeGen/IntrinsicLowering.cpp: + implement the lowering for this intrinsic
        6. + +
        7. llvm/lib/VMCore/Verifier.cpp: + Add code to check the invariants of the intrinsic are respected.
        8. + +
        9. llvm/lib/VMCore/Function.cpp (Function::getIntrinsicID()): + Identify the new intrinsic function, returning the enum for the intrinsic + that you added.
        10. + +
        11. llvm/lib/Analysis/BasicAliasAnalysis.cpp: If the new intrinsic does + not access memory or does not write to memory, add it to the relevant list + of functions.
        12. + +
        13. llvm/lib/Transforms/Utils/Local.cpp: If it is possible to constant + propagate your intrinsic, add support to it in the + canConstantFoldCallTo and ConstantFoldCall functions.
        14. + +
        15. Test your intrinsic
        16. +
        17. llvm/test/Regression/*: add your test cases to the test suite.
        18. +
        + +

        If this intrinsic requires code generator support (ie, it cannot be lowered). + You should also add support to the code generator in question.

        + +
        + + + + + +
        + +

        WARNING: adding instructions changes the bytecode + format, and it will take some effort to maintain compatibility with + the previous version. Only add an instruction if it is absolutely + necessary.

        + +
          + +
        1. llvm/include/llvm/Instruction.def: + add a number for your instruction and an enum name
        2. + +
        3. llvm/include/llvm/Instructions.h: + add a definition for the class that will represent your instruction
        4. + +
        5. llvm/include/llvm/Support/InstVisitor.h: + add a prototype for a visitor to your new instruction type
        6. + +
        7. llvm/lib/AsmParser/Lexer.l: + add a new token to parse your instruction from assembly text file
        8. + +
        9. llvm/lib/AsmParser/llvmAsmParser.y: + add the grammar on how your instruction can be read and what it will + construct as a result
        10. + +
        11. llvm/lib/Bytecode/Reader/InstructionReader.cpp: + add a case for your instruction and how it will be parsed from bytecode
        12. + +
        13. llvm/lib/VMCore/Instruction.cpp: + add a case for how your instruction will be printed out to assembly
        14. + +
        15. llvm/lib/VMCore/Instructions.cpp: + implement the class you defined in llvm/include/llvm/Instructions.h
        16. + +
        + +

        Also, you need to implement (or modify) any analyses or passes that you want + to understand this new instruction.

        + +
        + + + + + + +
        + +

        WARNING: adding new types changes the bytecode + format, and will break compatibility with currently-existing LLVM + installations. Only add new types if it is absolutely necessary.

        + +
        + + + + +
        + +
          + +
        1. llvm/include/llvm/Type.def: + add enum for the type
        2. + +
        3. llvm/include/llvm/Type.h: + add ID number for the new type; add static Type* for this type
        4. + +
        5. llvm/lib/VMCore/Type.cpp: + add mapping from TypeID => Type*; + initialize the static Type*
        6. + +
        7. llvm/lib/AsmReader/Lexer.l: + add ability to parse in the type from text assembly
        8. + +
        9. llvm/lib/AsmReader/llvmAsmParser.y: + add a token for that type
        10. + +
        + +
        + + + + +
        + +

        TODO

        + +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Misha Brukman
        + The LLVM Compiler Infrastructure +
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + + + Index: llvm-www/releases/1.3/docs/FAQ.html diff -c /dev/null llvm-www/releases/1.3/docs/FAQ.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/FAQ.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,533 ---- + + + + LLVM: Frequently Asked Questions + + + + +
        + LLVM: Frequently Asked Questions +
        + +
          +
        1. License +
            +
          1. Why are the LLVM source code and the front-end distributed under different + licenses?
          2. +
          3. Does the University of Illinois Open Source License really qualify as an + "open source" license?
          4. +
          5. Can I modify LLVM source code and redistribute the modified source?
          6. +
          7. Can I modify LLVM source code and redistribute binaries or other tools + based on it, without redistributing the source?
          8. +
        2. + +
        3. Source code +
            +
          1. In what language is LLVM written?
          2. +
          3. How portable is the LLVM source code?
          4. +
        4. + +
        5. Build Problems +
            +
          1. When I run configure, it finds the wrong C compiler.
          2. +
          3. I compile the code, and I get some error about /localhome.
          4. +
          5. The configure script finds the right C compiler, but it uses the + LLVM linker from a previous build. What do I do?
          6. +
          7. When creating a dynamic library, I get a strange GLIBC error.
          8. +
          9. I've updated my source tree from CVS, and now my build is trying to use a + file/directory that doesn't exist.
          10. +
          11. I've modified a Makefile in my source tree, but my build tree keeps using + the old version. What do I do?
          12. +
          13. I've upgraded to a new version of LLVM, and I get strange build + errors.
          14. +
          15. I've built LLVM and am testing it, but the tests freeze.
          16. +
          17. Why do test results differ when I perform different types of builds?
          18. +
          19. Compiling LLVM with GCC 3.3.2 fails, what should I do?
          20. +
          21. When I use the test suite, all of the C Backend tests fail. What is + wrong?
          22. +
        6. + +
        7. Using the GCC Front End +
            +
          1. + When I compile software that uses a configure script, the configure script + thinks my system has all of the header files and libraries it is testing + for. How do I get configure to work correctly? +
          2. + +
          3. + When I compile code using the LLVM GCC front end, it complains that it + cannot find libcrtend.a. +
          4. +
          +
        8. + +
        9. Questions about code generated by the GCC front-end +
            +
          1. What is this __main() call that gets inserted into + main()?
          2. +
          3. Where did all of my code go??
          4. +
          5. What is this llvm.global_ctors and + _GLOBAL__I__tmp_webcompile... stuff that happens when I + #include <iostream>?
          6. +
          +
        10. +
        + +
        +

        Written by The LLVM Team

        +
        + + + +
        + License +
        + + +
        +

        Why are the LLVM source code and the front-end distributed under different + licenses?

        +
        + +
        +

        The C/C++ front-ends are based on GCC and must be distributed under the GPL. + Our aim is to distribute LLVM source code under a much less restrictive + license, in particular one that does not compel users who distribute tools based + on modifying the source to redistribute the modified source code as well.

        +
        + +
        +

        Does the University of Illinois Open Source License really qualify as an + "open source" license?

        +
        + +
        +

        Yes, the license is certified by the Open + Source Initiative (OSI).

        +
        + +
        +

        Can I modify LLVM source code and redistribute the modified source?

        +
        + +
        +

        Yes. The modified source distribution must retain the copyright notice and + follow the three bulletted conditions listed in the LLVM license.

        +
        + +
        +

        Can I modify LLVM source code and redistribute binaries or other tools based + on it, without redistributing the source?

        +
        + +
        +

        Yes, this is why we distribute LLVM under a less restrictive license than + GPL, as explained in the first question above.

        +
        + + + + + +
        +

        In what language is LLVM written?

        +
        + +
        +

        All of the LLVM tools and libraries are written in C++ with extensive use of + the STL.

        +
        + +
        +

        How portable is the LLVM source code?

        +
        + +
        +

        The LLVM source code should be portable to most modern UNIX-like operating + systems. Most of the code is written in standard C++ with operating system + services abstracted to a support library. The tools required to build and test + LLVM have been ported to a plethora of platforms.

        + +

        Some porting problems may exist in the following areas:

        + +
          + +
        • The GCC front end code is not as portable as the LLVM suite, so it may not + compile as well on unsupported platforms.
        • + +
        • The Python test classes are more UNIX-centric than they should be, so + porting to non-UNIX like platforms (i.e. Windows, MacOS 9) will require some + effort.
        • + +
        • The LLVM build system relies heavily on UNIX shell tools, like the Bourne + Shell and sed. Porting to systems without these tools (MacOS 9, Plan 9) will + require more effort.
        • + +
        + +
        + + + + + +
        +

        When I run configure, it finds the wrong C compiler.

        +
        + +
        + +

        The configure script attempts to locate first gcc and then + cc, unless it finds compiler paths set in CC and CXX + for the C and C++ compiler, respectively.

        + +

        If configure finds the wrong compiler, either adjust your + PATH environment variable or set CC and CXX + explicitly.

        + +
        + +
        +

        I compile the code, and I get some error about /localhome.

        +
        + +
        + +

        There are several possible causes for this. The first is that you didn't set + a pathname properly when using configure, and it defaulted to a + pathname that we use on our research machines.

        + +

        Another possibility is that we hardcoded a path in our Makefiles. If you see + this, please email the LLVM bug mailing list with the name of the offending + Makefile and a description of what is wrong with it.

        + +
        + +
        +

        The configure script finds the right C compiler, but it uses the + LLVM linker from a previous build. What do I do?

        +
        + +
        +

        The configure script uses the PATH to find executables, so + if it's grabbing the wrong linker/assembler/etc, there are two ways to fix + it:

        + +
          + +
        1. Adjust your PATH environment variable so that the correct + program appears first in the PATH. This may work, but may not be + convenient when you want them first in your path for other + work.

        2. + +
        3. Run configure with an alternative PATH that is + correct. In a Borne compatible shell, the syntax would be:

          + +

          PATH=[the path without the bad program] ./configure ...

          + +

          This is still somewhat inconvenient, but it allows configure + to do its work without having to adjust your PATH + permanently.

        4. + +
        + +
        + +
        +

        When creating a dynamic library, I get a strange GLIBC error.

        +
        + +
        +

        Under some operating systems (i.e. Linux), libtool does not work correctly if + GCC was compiled with the --disable-shared option. To work around this, install + your own version of GCC that has shared libraries enabled by default.

        +
        + +
        +

        I've updated my source tree from CVS, and now my build is trying to use a + file/directory that doesn't exist.

        +
        + +
        +

        You need to re-run configure in your object directory. When new Makefiles + are added to the source tree, they have to be copied over to the object tree in + order to be used by the build.

        +
        + +
        +

        I've modified a Makefile in my source tree, but my build tree keeps using the + old version. What do I do?

        +
        + +
        + +

        If the Makefile already exists in your object tree, you + can just run the following command in the top level directory of your object + tree:

        + +

        ./config.status <relative path to Makefile>

        + +

        If the Makefile is new, you will have to modify the configure script to copy + it over.

        + +
        + +
        +

        I've upgraded to a new version of LLVM, and I get strange build errors.

        +
        + +
        + +

        Sometimes, changes to the LLVM source code alters how the build system works. + Changes in libtool, autoconf, or header file dependencies are especially prone + to this sort of problem.

        + +

        The best thing to try is to remove the old files and re-build. In most + cases, this takes care of the problem. To do this, just type make + clean and then make in the directory that fails to build.

        + +
        + +
        +

        I've built LLVM and am testing it, but the tests freeze.

        +
        + +
        + +

        This is most likely occurring because you built a profile or release + (optimized) build of LLVM and have not specified the same information on the + gmake command line.

        + +

        For example, if you built LLVM with the command:

        + +

        gmake ENABLE_PROFILING=1 + +

        ...then you must run the tests with the following commands:

        + +

        cd llvm/test
        gmake ENABLE_PROFILING=1

        + +
        + +
        +

        Why do test results differ when I perform different types of builds?

        +
        + +
        + +

        The LLVM test suite is dependent upon several features of the LLVM tools and + libraries.

        + +

        First, the debugging assertions in code are not enabled in optimized or + profiling builds. Hence, tests that used to fail may pass.

        + +

        Second, some tests may rely upon debugging options or behavior that is only + available in the debug build. These tests will fail in an optimized or profile + build.

        + +
        + +
        +

        Compiling LLVM with GCC 3.3.2 fails, what should I do?

        +
        + +
        +

        This is a bug in GCC, and + affects projects other than LLVM. Try upgrading or downgrading your GCC.

        +
        + +
        +

        + When I use the test suite, all of the C Backend tests fail. What is + wrong? +

        +
        + +
        +

        + If you build LLVM and the C Backend tests fail in llvm/test/Programs, + then chances are good that the directory pointed to by the LLVM_LIB_SEARCH_PATH + environment variable does not contain the libcrtend.a library. +

        + +

        + To fix it, verify that LLVM_LIB_SEARCH_PATH points to the correct directory + and that libcrtend.a is inside. For pre-built LLVM GCC front ends, this + should be the absolute path to + cfrontend/<platform>/llvm-gcc/bytecode-libs. If you've + built your own LLVM GCC front end, then ensure that you've built and installed + the libraries in llvm/runtime and have LLVM_LIB_SEARCH_PATH pointing + to the LLVMGCCDIR/bytecode-libs subdirectory. +

        +
        + + + + +
        +

        + When I compile software that uses a configure script, the configure script + thinks my system has all of the header files and libraries it is testing for. + How do I get configure to work correctly? +

        +
        + +
        +

        + The configure script is getting things wrong because the LLVM linker allows + symbols to be undefined at link time (so that they can be resolved during JIT + or translation to the C back end). That is why configure thinks your system + "has everything." +

        +

        + To work around this, perform the following steps: +

        + +
          +
        1. + Make sure the CC and CXX environment variables contains the full path to the + LLVM GCC front end. +
        2. + +
        3. + Make sure that the regular C compiler is first in your PATH. +
        4. + +
        5. + Add the string "-Wl,-native" to your CFLAGS environment variable. +
        6. +
        + +

        + This will allow the gccld linker to create a native code executable instead of + a shell script that runs the JIT. Creating native code requires standard + linkage, which in turn will allow the configure script to find out if code is + not linking on your system because the feature isn't available on your system. +

        +
        + +
        +

        + When I compile code using the LLVM GCC front end, it complains that it cannot + find libcrtend.a. +

        +
        + +
        +

        + In order to find libcrtend.a, you must have the directory in which it lives in + your LLVM_LIB_SEARCH_PATH environment variable. For the binary distribution of + the LLVM GCC front end, this will be the full path of the bytecode-libs + directory inside of the LLVM GCC distribution. +

        +
        + + + + + +

        + What is this __main() call that gets inserted into main()? +

        + +
        +

        + The __main call is inserted by the C/C++ compiler in order to guarantee + that static constructors and destructors are called when the program starts up + and shuts down. In C, you can create static constructors and destructors by + using GCC extensions, and in C++ you can do so by creating a global variable + whose class has a ctor or dtor. +

        + +

        + The actual implementation of __main lives in the + llvm/runtime/GCCLibraries/crtend/ directory in the source-base, and is + linked in automatically when you link the program. +

        +
        + + + +

        + Where did all of my code go?? +

        + +
        +

        + If you are using the LLVM demo page, you may often wonder what happened to all + of the code that you typed in. Remember that the demo script is running the + code through the LLVM optimizers, so if your code doesn't actually do anything + useful, it might all be deleted. +

        + +

        + To prevent this, make sure that the code is actually needed. For example, if + you are computing some expression, return the value from the function instead of + leaving it in a local variable. If you really want to constrain the optimizer, + you can read from and assign to volatile global variables. +

        +
        + + + +

        + What is this llvm.global_ctors and _GLOBAL__I__tmp_webcompile... stuff that happens when I #include <iostream>? +

        + +
        +

        + If you #include the <iostream> header into a C++ translation unit, the + file will probably use the std::cin/std::cout/... global + objects. However, C++ does not guarantee an order of initialization between + static objects in different translation units, so if a static ctor/dtor in your + .cpp file used std::cout, for example, the object would not necessarily + be automatically initialized before your use. +

        + +

        + To make std::cout and friends work correctly in these scenarios, the + STL that we use declares a static object that gets created in every translation + unit that includes <iostream>. This object has a static constructor and + destructor that initializes and destroys the global iostream objects before they + could possibly be used in the file. The code that you see in the .ll file + corresponds to the constructor and destructor registration code. +

        + +

        + If you would like to make it easier to understand the LLVM code generated + by the compiler in the demo page, consider using printf instead of iostreams to + print values. +

        +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + + + Index: llvm-www/releases/1.3/docs/GarbageCollection.html diff -c /dev/null llvm-www/releases/1.3/docs/GarbageCollection.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/GarbageCollection.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,533 ---- + + + + Accurate Garbage Collection with LLVM + + + + +
        + Accurate Garbage Collection with LLVM +
        + +
          +
        1. Introduction + +
        2. + +
        3. Interfaces for user programs + +
        4. + +
        5. Implementing a garbage collector + +
        6. +
        7. GC implementations available + +
        8. + + +
        + +
        +

        Written by Chris Lattner

        +
        + + + + + +
        + +

        Garbage collection is a widely used technique that frees the programmer from + having to know the life-times of heap objects, making software easier to produce + and maintain. Many programming languages rely on garbage collection for + automatic memory management. There are two primary forms of garbage collection: + conservative and accurate.

        + +

        Conservative garbage collection often does not require any special support + from either the language or the compiler: it can handle non-type-safe + programming languages (such as C/C++) and does not require any special + information from the compiler. The [LINK] Boehm collector is an example of a + state-of-the-art conservative collector.

        + +

        Accurate garbage collection requires the ability to identify all pointers in + the program at run-time (which requires that the source-language be type-safe in + most cases). Identifying pointers at run-time requires compiler support to + locate all places that hold live pointer variables at run-time, including the + processor stack and registers.

        + +

        + Conservative garbage collection is attractive because it does not require any + special compiler support, but it does have problems. In particular, because the + conservative garbage collector cannot know that a particular word in the + machine is a pointer, it cannot move live objects in the heap (preventing the + use of compacting and generational GC algorithms) and it can occasionally suffer + from memory leaks due to integer values that happen to point to objects in the + program. In addition, some aggressive compiler transformations can break + conservative garbage collectors (though these seem rare in practice). +

        + +

        + Accurate garbage collectors do not suffer from any of these problems, but they + can suffer from degraded scalar optimization of the program. In particular, + because the runtime must be able to identify and update all pointers active in + the program, some optimizations are less effective. In practice, however, the + locality and performance benefits of using aggressive garbage allocation + techniques dominates any low-level losses. +

        + +

        + This document describes the mechanisms and interfaces provided by LLVM to + support accurate garbage collection. +

        + +
        + + + + +
        + +

        + LLVM provides support for a broad class of garbage collection algorithms, + including compacting semi-space collectors, mark-sweep collectors, generational + collectors, and even reference counting implementations. It includes support + for read and write barriers, and associating meta-data with stack objects (used for tagless garbage + collection). All LLVM code generators support garbage collection, including the + C backend. +

        + +

        + We hope that the primitive support built into LLVM is sufficient to support a + broad class of garbage collected languages, including Scheme, ML, scripting + languages, Java, C#, etc. That said, the implemented garbage collectors may + need to be extended to support language-specific features such as finalization, + weak references, or other features. As these needs are identified and + implemented, they should be added to this specification. +

        + +

        + LLVM does not currently support garbage collection of multi-threaded programs or + GC-safe points other than function calls, but these will be added in the future + as there is interest. +

        + +
        + + + + + +
        + +

        This section describes the interfaces provided by LLVM and by the garbage + collector run-time that should be used by user programs. As such, this is the + interface that front-end authors should generate code for. +

        + +
        + + + + +
        + +
        + void %llvm.gcroot(<ty>** %ptrloc, <ty2>* %metadata) +
        + +

        + The llvm.gcroot intrinsic is used to inform LLVM of a pointer variable + on the stack. The first argument contains the address of the variable on the + stack, and the second contains a pointer to metadata that should be associated + with the pointer (which must be a constant or global value address). At + runtime, the llvm.gcroot intrinsic stores a null pointer into the + specified location to initialize the pointer.

        + +

        + Consider the following fragment of Java code: +

        + +
        +        {
        +          Object X;   // A null-initialized reference to an object
        +          ...
        +        }
        + 
        + +

        + This block (which may be located in the middle of a function or in a loop nest), + could be compiled to this LLVM code: +

        + +
        + Entry:
        +    ;; In the entry block for the function, allocate the
        +    ;; stack space for X, which is an LLVM pointer.
        +    %X = alloca %Object*
        +    ...
        + 
        +    ;; "CodeBlock" is the block corresponding to the start
        +    ;;  of the scope above.
        + CodeBlock:
        +    ;; Initialize the object, telling LLVM that it is now live.
        +    ;; Java has type-tags on objects, so it doesn't need any
        +    ;; metadata.
        +    call void %llvm.gcroot(%Object** %X, sbyte* null)
        +    ...
        + 
        +    ;; As the pointer goes out of scope, store a null value into
        +    ;; it, to indicate that the value is no longer live.
        +    store %Object* null, %Object** %X
        +    ...
        + 
        + +
        + + + + +
        + +
        + sbyte *%llvm_gc_allocate(unsigned %Size) +
        + +

        The llvm_gc_allocate function is a global function defined by the + garbage collector implementation to allocate memory. It returns a + zeroed-out block of memory of the appropriate size.

        + +
        + + + + +
        + +
        + sbyte *%llvm.gcread(sbyte *, sbyte **)
        + void %llvm.gcwrite(sbyte*, sbyte*, sbyte**) +
        + +

        Several of the more interesting garbage collectors (e.g., generational + collectors) need to be informed when the mutator (the program that needs garbage + collection) reads or writes object references into the heap. In the case of a + generational collector, it needs to keep track of which "old" generation objects + have references stored into them. The amount of code that typically needs to be + executed is usually quite small (and not on the critical path of any + computation), so the overall performance impact of the inserted code is + tolerable.

        + +

        To support garbage collectors that use read or write barriers, LLVM provides + the llvm.gcread and llvm.gcwrite intrinsics. The first + intrinsic has exactly the same semantics as a non-volatile LLVM load and the + second has the same semantics as a non-volatile LLVM store, with the + additions that they also take a pointer to the start of the memory + object as an argument. At code generation + time, these intrinsics are replaced with calls into the garbage collector + (llvm_gc_read and llvm_gc_write respectively), which are then + inlined into the code. +

        + +

        + If you are writing a front-end for a garbage collected language, every load or + store of a reference from or to the heap should use these intrinsics instead of + normal LLVM loads/stores.

        + +
        + + + + +
        + +
        + void %llvm_gc_initialize(unsigned %InitialHeapSize) +
        + +

        + The llvm_gc_initialize function should be called once before any other + garbage collection functions are called. This gives the garbage collector the + chance to initialize itself and allocate the heap spaces. The initial heap size + to allocate should be specified as an argument. +

        + +
        + + + + +
        + +
        + void %llvm_gc_collect() +
        + +

        + The llvm_gc_collect function is exported by the garbage collector + implementations to provide a full collection, even when the heap is not + exhausted. This can be used by end-user code as a hint, and may be ignored by + the garbage collector. +

        + +
        + + + + + + +
        + +

        + Implementing a garbage collector for LLVM is fairly straight-forward. The LLVM + garbage collectors are provided in a form that makes them easy to link into the + language-specific runtime that a language front-end would use. They require + functionality from the language-specific runtime to get information about where pointers are located in heap objects. +

        + +

        The + implementation must include the llvm_gc_allocate and llvm_gc_collect functions, and it must implement + the read/write barrier functions as well. To + do this, it will probably have to trace through the roots + from the stack and understand the GC descriptors + for heap objects. Luckily, there are some example + implementations available. +

        +
        + + + + + +
        +
        + void *llvm_gc_read(void*, void **)
        + void llvm_gc_write(void*, void *, void**) +
        + +

        + These functions must be implemented in every garbage collector, even if + they do not need read/write barriers. In this case, just load or store the + pointer, then return. +

        + +

        + If an actual read or write barrier is needed, it should be straight-forward to + implement it. +

        + +
        + + + + +
        +

        + Garbage collector implementations make use of call-back functions that are + implemented by other parts of the LLVM system. +

        +
        + + + + +
        +
        + void llvm_cg_walk_gcroots(void (*FP)(void **Root, void *Meta)); +
        + +

        + The llvm_cg_walk_gcroots function is a function provided by the code + generator that iterates through all of the GC roots on the stack, calling the + specified function pointer with each record. For each GC root, the address of + the pointer and the meta-data (from the llvm.gcroot intrinsic) are provided. +

        +
        + + + + +
        + TODO +
        + + + + + +
        +

        + The three most common ways to keep track of where pointers live in heap objects + are (listed in order of space overhead required):

        + +
          +
        1. In languages with polymorphic objects, pointers from an object header are + usually used to identify the GC pointers in the heap object. This is common for + object-oriented languages like Self, Smalltalk, Java, or C#.
        2. + +
        3. If heap objects are not polymorphic, often the "shape" of the heap can be + determined from the roots of the heap or from some other meta-data [Appel89, Goldberg91, Tolmach94]. In this case, the garbage collector can + propagate the information around from meta data stored with the roots. This + often eliminates the need to have a header on objects in the heap. This is + common in the ML family.
        4. + +
        5. If all heap objects have pointers in the same locations, or pointers can be + distinguished just by looking at them (e.g., the low order bit is clear), no + book-keeping is needed at all. This is common for Lisp-like languages.
        6. +
        + +

        The LLVM garbage collectors are capable of supporting all of these styles of + language, including ones that mix various implementations. To do this, it + allows the source-language to associate meta-data with the stack roots, and the heap tracing routines can propagate the + information. In addition, LLVM allows the front-end to extract GC information + from in any form from a specific object pointer (this supports situations #1 and + #3). +

        + +

        Making this efficient

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

        + To make this more concrete, the currently implemented LLVM garbage collectors + all live in the llvm/runtime/GC/* directories in the LLVM source-base. + If you are interested in implementing an algorithm, there are many interesting + possibilities (mark/sweep, a generational collector, a reference counting + collector, etc), or you could choose to improve one of the existing algorithms. +

        + +
        + + + + +
        +

        + SemiSpace is a very simple copying collector. When it starts up, it allocates + two blocks of memory for the heap. It uses a simple bump-pointer allocator to + allocate memory from the first block until it runs out of space. When it runs + out of space, it traces through all of the roots of the program, copying blocks + to the other half of the memory space. +

        + +
        + + +
        + Possible Improvements +
        + +
        + +

        + If a collection cycle happens and the heap is not compacted very much (say less + than 25% of the allocated memory was freed), the memory regions should be + doubled in size.

        + +
        + + + + + +
        + +

        [Appel89] Runtime Tags Aren't Necessary. Andrew + W. Appel. Lisp and Symbolic Computation 19(7):703-705, July 1989.

        + +

        [Goldberg91] Tag-free garbage collection for + strongly typed programming languages. Benjamin Goldberg. ACM SIGPLAN + PLDI'91.

        + +

        [Tolmach94] Tag-free garbage collection using + explicit type parameters. Andrew Tolmach. Proceedings of the 1994 ACM + conference on LISP and functional programming.

        + +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
        + LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + + + Index: llvm-www/releases/1.3/docs/GettingStarted.html diff -c /dev/null llvm-www/releases/1.3/docs/GettingStarted.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/GettingStarted.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,1274 ---- + + + + Getting Started with LLVM System + + + + +
        + Getting Started with the LLVM System +
        + + + +
        +

        Written by: + John Criswell, + Chris Lattner, + Misha Brukman, + Vikram Adve, and + Guochun Shi. +

        +
        + + + +
        + Overview +
        + + +
        + +

        Welcome to LLVM! In order to get started, you first need to know some + basic information.

        + +

        First, LLVM comes in two pieces. The first piece is the LLVM suite. This + contains all of the tools, libraries, and header files needed to use the low + level virtual machine. It contains an assembler, disassembler, bytecode + analyzer, and bytecode optimizer. It also contains a test suite that can be + used to test the LLVM tools and the GCC front end.

        + +

        The second piece is the GCC front end. This component provides a version of + GCC that compiles C and C++ code into LLVM bytecode. Currently, the GCC front + end is a modified version of GCC 3.4 (we track the GCC 3.4 development). Once + compiled into LLVM bytecode, a program can be manipulated with the LLVM tools + from the LLVM suite.

        + +
        + + + + + +
        + +

        Here's the short story for getting up and running quickly with LLVM:

        + +
          +
        1. Install the GCC front end: +
            +
          1. cd where-you-want-the-C-front-end-to-live +
          2. gunzip --stdout cfrontend.platform.tar.gz | tar -xvf - +
          3. Sparc and MacOS X Only:
            + cd cfrontend/platform
            + ./fixheaders
            +
        2. + +
        3. Get the Source Code +
            +
          • With the distributed files: +
              +
            1. cd where-you-want-llvm-to-live +
            2. gunzip --stdout llvm-version.tar.gz | tar -xvf - +
            3. cd llvm +
          • + +
          • With anonymous CVS access (or use a mirror): +
              +
            1. cd where-you-want-llvm-to-live
            2. +
            3. cvs -d + :pserver:anon at llvm-cvs.cs.uiuc.edu:/var/cvs/llvm login
            4. +
            5. Hit the return key when prompted for the password. +
            6. cvs -z3 -d :pserver:anon at llvm-cvs.cs.uiuc.edu:/var/cvs/llvm + co llvm
            7. +
            8. cd llvm
            9. +
          • +
        4. + +
        5. Configure the LLVM Build Environment +
            +
          1. Change directory to where you want to store the LLVM object + files and run configure to configure the Makefiles and + header files for the default platform. Useful options include: +
              +
            • --with-llvmgccdir=directory +

              Specify the full pathname of where the LLVM GCC frontend is + installed.

            • +
            • --enable-spec2000=directory +

              Enable the SPEC2000 benchmarks for testing. The SPEC2000 + benchmarks should be available in + directory.

            • +
            +
        6. + +
        7. Build the LLVM Suite: +
            +
          1. Set your LLVM_LIB_SEARCH_PATH environment variable.
          2. +
          3. gmake -k |& tee gnumake.out +    # this is csh or tcsh syntax
          4. +
          5. If you get an "internal compiler error (ICE)" see below.
          6. +
          + +
        + +

        Consult the Getting Started with LLVM section for + detailed information on configuring and compiling LLVM. See Setting Up Your Environment for tips that simplify + working with the GCC front end and LLVM tools. Go to Program + Layout to learn about the layout of the source code tree.

        + +
        + + + + + +
        + +

        Before you begin to use the LLVM system, review the requirements given below. + This may save you some trouble by knowing ahead of time what hardware and + software you will need.

        + +
        + + +
        + Hardware +
        + +
        + +

        LLVM is known to work on the following platforms:

        + +
          + +
        • Linux on x86 (Pentium and above) +
            +
          • Approximately 2.6 GB of Free Disk Space +
              +
            • Source code: 57 MB
            • +
            • Object code: 2.5 GB
            • +
            • GCC front end: 30 MB
            • +
          • +
          +
        • + +
        • Solaris on SparcV9 (Ultrasparc) +
            +
          • Approximately 2.6 GB of Free Disk Space +
              +
            • Source code: 57 MB
            • +
            • Object code: 2.5 GB
            • +
            • GCC front end: 46 MB
            • +
          • +
          +
        • + +
        • FreeBSD on x86 (Pentium and above) +
            +
          • Approximately 1 GB of Free Disk Space +
              +
            • Source code: 57 MB
            • +
            • Object code: 850 MB
            • +
            • GCC front end: 40 MB
            • +
          • +
          +
        • + +
        • MacOS X on PowerPC +
            +
          • Experimental support for static native code generation +
          • Approximately 1.6 GB of Free Disk Space +
              +
            • Source code: 57 MB
            • +
            • Object code: 1.5 GB
            • +
            • GCC front end: 36 MB
            • +
          • +
          + +
        • +
        + +

        The LLVM suite may compile on other platforms, but it is not + guaranteed to do so. If compilation is successful, the LLVM utilities should be + able to assemble, disassemble, analyze, and optimize LLVM bytecode. Code + generation should work as well, although the generated native code may not work + on your platform.

        + +

        The GCC front end is not very portable at the moment. If you want to get it + to work on another platform, you can download a copy of the source and try to compile it on your platform.

        + +
        + + +
        + Software +
        + +
        + +

        Compiling LLVM requires that you have several software packages + installed:

        + + + +

        There are some additional tools that you may want to have when working with + LLVM:

        + +
          +
        • 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). You will also need automake. Any old version of + automake from 1.4p5 on should work; we only use aclocal from that + package.

        • + +
        • QMTest 2.0.3
        • +
        • Python + +

          + These are needed to use the LLVM test suite. Please note that newer + versions of QMTest may not work with the LLVM test suite. QMTest 2.0.3 + can be retrieved from the QMTest CVS repository using the following + commands:

          +
            +
          • cvs -d :pserver:anoncvs at cvs.codesourcery.com:/home/qm/Repository login +
          • +
          • When prompted, use anoncvs as the password. +
          • +
          • cvs -d :pserver:anoncvs at cvs.codesourcery.com:/home/qm/Repository co -r release-2-0-3 qm +
          • +
          +
        • + +
        +
        + + + + +
        + +

        LLVM is very demanding of the host C++ compiler, and as such tends to expose + bugs in the compiler. In particular, several versions of GCC crash when trying + to compile LLVM. We routinely use GCC 3.3.3 and GCC 3.4.0 and have had success + with them. Other versions of GCC will probably work as well. GCC versions listed + here are known to not work. If you are using one of these versions, please try + to upgrade your GCC to something more recent. If you run into a problem with a + version of GCC not listed here, please let + us know. Please use the "gcc -v" command to find out which version + of GCC you are using. +

        + +

        GCC versions prior to 3.0: GCC 2.96.x and before had several + problems in the STL that effectively prevent it from compiling LLVM. +

        + +

        GCC 3.3.2: This version of GCC suffered from a serious bug which causes it to crash in + the "convert_from_eh_region_ranges_1" GCC function.

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

        The remainder of this guide is meant to get you up and running with + LLVM and to give you some basic information about the LLVM environment.

        + +

        The later sections of this guide describe the general layout of the the LLVM source tree, a simple example using the LLVM tool chain, and links to find more information about LLVM or to get + help via e-mail.

        +
        + + + + +
        + +

        Throughout this manual, the following names are used to denote paths + specific to the local system and working environment. These are not + environment variables you need to set but just strings used in the rest + of this document below. In any of the examples below, simply replace + each of these names with the appropriate pathname on your local system. + All these paths are absolute:

        + +
        +
        SRC_ROOT +
        + This is the top level directory of the LLVM source tree. +

        + +

        OBJ_ROOT +
        + This is the top level directory of the LLVM object tree (i.e. the + tree where object files and compiled programs will be placed. It + can be the same as SRC_ROOT). +

        + +

        LLVMGCCDIR +
        + This is the where the LLVM GCC Front End is installed. +

        + For the pre-built GCC front end binaries, the LLVMGCCDIR is + cfrontend/platform/llvm-gcc. +

        + +
        + + + + +
        + +

        + In order to compile and use LLVM, you will need to set some environment + variables. There are also some shell aliases which you may find useful. + You can set these on the command line, or better yet, set them in your + .cshrc or .profile. + +

        +
        LLVM_LIB_SEARCH_PATH=LLVMGCCDIR/bytecode-libs +
        + This environment variable helps the LLVM GCC front end find bytecode + libraries that it will need for compilation. +

        + +

        alias llvmgcc LLVMGCCDIR/bin/gcc +
        alias llvmg++ LLVMGCCDIR/bin/g++ +
        + This alias allows you to use the LLVM C and C++ front ends without putting + them in your PATH or typing in their complete pathnames. +
        + +
        + + + + +
        + +

        + If you have the LLVM distribution, you will need to unpack it before you + can begin to compile it. LLVM is distributed as a set of two files: the LLVM + suite and the LLVM GCC front end compiled for your platform. Each + file is a TAR archive that is compressed with the gzip program. +

        + +

        The files are as follows: +

        +
        llvm-1.3.tar.gz +
        This is the source code to the LLVM suite. +

        + +

        cfrontend-1.3.sparc-sun-solaris2.8.tar.gz +
        This is the binary release of the GCC front end for Solaris/Sparc. +

        + +

        cfrontend-1.3.i686-redhat-linux-gnu.tar.gz +
        This is the binary release of the GCC front end for Linux/x86. +

        + +

        cfrontend-1.3.i386-unknown-freebsd5.1.tar.gz +
        This is the binary release of the GCC front end for FreeBSD/x86. +

        + +

        cfrontend-1.3.powerpc-apple-darwin7.0.0.tar.gz +
        This is the binary release of the GCC front end for MacOS X/PPC. +
        + +
        + + + + +
        + +

        If you have access to our CVS repository, you can get a fresh copy of + the entire source code. All you need to do is check it out from CVS as + follows:

        + +
          +
        • cd where-you-want-llvm-to-live +
        • cvs -d :pserver:anon at llvm-cvs.cs.uiuc.edu:/var/cvs/llvm login +
        • Hit the return key when prompted for the password. +
        • cvs -z3 -d :pserver:anon at llvm-cvs.cs.uiuc.edu:/var/cvs/llvm co + llvm +
        + +

        This will create an 'llvm' directory in the current + directory and fully populate it with the LLVM source code, Makefiles, + test directories, and local copies of documentation files.

        + +

        If you want to get a specific release (as opposed to the most recent + revision), you can specify a label. The following releases have the following + label:

        + +
          +
        • Release 1.3: RELEASE_13
        • +
        • Release 1.2: RELEASE_12
        • +
        • Release 1.1: RELEASE_11
        • +
        • Release 1.0: RELEASE_1
        • +
        + +

        If you would like to get the GCC front end source code, you can also get it + from the CVS repository:

        + +
        +   cvs -z3 -d :pserver:anon at llvm-cvs.cs.uiuc.edu:/var/cvs/llvm co llvm-gcc
        + 
        + +

        Please note that you must follow these + instructions to successfully build the LLVM C front-end.

        + +
        + + + + +
        + +

        If the main CVS server is overloaded or inaccessible, you can try one of + these user-hosted mirrors:

        + + +
        + + + + +
        + +

        Before configuring and compiling the LLVM suite, you need to extract the LLVM + GCC front end from the binary distribution. It is used for building the + bytecode libraries later used by the GCC front end for linking programs, and its + location must be specified when the LLVM suite is configured.

        + +

        To install the GCC front end, do the following:

        + +
          +
        1. cd where-you-want-the-front-end-to-live
        2. +
        3. gunzip --stdout cfrontend-version.platform.tar.gz | tar -xvf + -
        4. +
        + +

        If you are using Solaris/Sparc or MacOS X/PPC, you will need to fix the + header files:

        + +

        cd cfrontend/platform
        + ./fixheaders

        + +

        The binary versions of the GCC front end may not suit all of your needs. For + example, the binary distribution may include an old version of a system header + file, not "fix" a header file that needs to be fixed for GCC, or it may be + linked with libraries not available on your system.

        + +

        In cases like these, you may want to try building the GCC front end from source. This is + not for the faint of heart, so be forewarned.

        + +
        + + + + +
        + +

        Once checked out from the CVS repository, the LLVM suite source code must be + configured via the configure script. This script sets variables in + llvm/Makefile.config and llvm/include/Config/config.h. It + also populates OBJ_ROOT with the Makefiles needed to begin building + LLVM.

        + +

        The following environment variables are used by the configure + script to configure the build system:

        + + + + + + + + + + + + + + + + +
        VariablePurpose
        CCTells configure which C compiler to use. By default, + configure will look for the first GCC C compiler in + PATH. Use this variable to override + configure's default behavior.
        CXXTells configure which C++ compiler to use. By default, + configure will look for the first GCC C++ compiler in + PATH. Use this variable to override + configure's default behavior.
        + +

        The following options can be used to set or enable LLVM specific options:

        + +
        +
        --with-llvmgccdir=LLVMGCCDIR +
        + Path to the location where the LLVM GCC front end binaries and + associated libraries were installed. This must be specified as an + absolute pathname. +

        +

        --enable-optimized +
        + Enables optimized compilation by default (debugging symbols are removed + and GCC optimization flags are enabled). The default is to use an + unoptimized build (also known as a debug build). +

        +

        --enable-jit +
        + Compile the Just In Time (JIT) compiler functionality. This is not + available + on all platforms. The default is dependent on platform, so it is best + to explicitly enable it if you want it. +

        +

        --enable-spec2000 +
        --enable-spec2000=<directory> +
        + Enable the use of SPEC2000 when testing LLVM. This is disabled by default + (unless configure finds SPEC2000 installed). By specifying + directory, you can tell configure where to find the SPEC2000 + benchmarks. If directory is left unspecified, configure + uses the default value + /home/vadve/shared/benchmarks/speccpu2000/benchspec. +

        +

        --enable-spec95 +
        --enable-spec95=<directory> +
        + Enable the use of SPEC95 when testing LLVM. It is similar to the + --enable-spec2000 option. +

        +

        --enable-povray +
        --enable-povray=<directory> +
        + Enable the use of Povray as an external test. Versions of Povray written + in C should work. This option is similar to the --enable-spec2000 + option. +
        + +

        To configure LLVM, follow these steps:

        + +
          +
        1. Change directory into the object root directory: +
          + cd OBJ_ROOT +

          + +

        2. Run the configure script located in the LLVM source tree: +
          + SRC_ROOT/configure +

          +

        + +

        In addition to running configure, you must set the + LLVM_LIB_SEARCH_PATH environment variable in your startup scripts. + This environment variable is used to locate "system" libraries like + "-lc" and "-lm" when linking. This variable should be set to + the absolute path of the bytecode-libs subdirectory of the GCC front + end, or LLVMGCCDIR/bytecode-libs. For example, one might set + LLVM_LIB_SEARCH_PATH to + /home/vadve/lattner/local/x86/llvm-gcc/bytecode-libs for the x86 + version of the GCC front end on our research machines.

        + +
        + + + + +
        + +

        Once you have configured LLVM, you can build it. There are three types of + builds:

        + +
        +
        Debug Builds +
        + These builds are the default when one types gmake (unless the + --enable-optimized option was used during configuration). The + build system will compile the tools and libraries with debugging + information. +

        + +

        Release (Optimized) Builds +
        + These builds are enabled with the --enable-optimized option to + configure or by specifying ENABLE_OPTIMIZED=1 on the + gmake command line. For these builds, the build system will + compile the tools and libraries with GCC optimizations enabled and strip + debugging information from the libraries and executables it generates. +

        + +

        Profile Builds +
        + These builds are for use with profiling. They compile profiling + information into the code for use with programs like gprof. + Profile builds must be started by specifying ENABLE_PROFILING=1 + on the gmake command line. +
        + +

        Once you have LLVM configured, you can build it by entering the + OBJ_ROOT directory and issuing the following command:

        + +

        gmake

        + +

        If the build fails, please check here to see if you + are using a known broken version of GCC to compile LLVM with.

        + +

        + If you have multiple processors in your machine, you may wish to use some of + the parallel build options provided by GNU Make. For example, you could use the + command:

        + +

        gmake -j2

        + +

        There are several special targets which are useful when working with the LLVM + source code:

        + +
        +
        gmake clean +
        + Removes all files generated by the build. This includes object files, + generated C/C++ files, libraries, and executables. +

        + +

        gmake distclean +
        + Removes everything that gmake clean does, but also removes + files generated by configure. It attempts to return the + source tree to the original state in which it was shipped. +

        + +

        gmake install +
        + Installs LLVM files into the proper location. For the most part, + this does nothing, but it does install bytecode libraries into the + GCC front end's bytecode library directory. If you need to update + your bytecode libraries, this is the target to use once you've built + them. +

        +

        + +

        It is also possible to override default values from configure by + declaring variables on the command line. The following are some examples:

        + +
        +
        gmake ENABLE_OPTIMIZED=1 +
        + Perform a Release (Optimized) build. +

        + +

        gmake ENABLE_PROFILING=1 +
        + Perform a Profiling build. +

        + +

        gmake VERBOSE=1 +
        + Print what gmake is doing on standard output. +

        +

        + +

        Every directory in the LLVM object tree includes a Makefile to build + it and any subdirectories that it contains. Entering any directory inside the + LLVM object tree and typing gmake should rebuild anything in or below + that directory that is out of date.

        + +
        + + + + +
        + +

        The LLVM build system is capable of sharing a single LLVM source tree among + several LLVM builds. Hence, it is possible to build LLVM for several different + platforms or configurations using the same source tree.

        + +

        This is accomplished in the typical autoconf manner:

        + +
          +
        • Change directory to where the LLVM object files should live:

          + +

          cd OBJ_ROOT

        • + +
        • Run the configure script found in the LLVM source + directory:

          + +

          SRC_ROOT/configure

        • +
        + +

        The LLVM build will place files underneath OBJ_ROOT in directories + named after the build type:

        + +
        +
        Debug Builds +
        +
        +
        Tools +
        OBJ_ROOT/tools/Debug +
        Libraries +
        OBJ_ROOT/lib/Debug +
        +

        + +

        Release Builds +
        +
        +
        Tools +
        OBJ_ROOT/tools/Release +
        Libraries +
        OBJ_ROOT/lib/Release +
        +

        + +

        Profile Builds +
        +
        +
        Tools +
        OBJ_ROOT/tools/Profile +
        Libraries +
        OBJ_ROOT/lib/Profile +
        +
        + +
        + + + + +
        + +

        + If you're running on a linux system that supports the "binfmt_misc" + module, and you have root access on the system, you can set your system up to + execute LLVM bytecode files directly. To do this, use commands like this (the + first command may not be required if you are already using the module):

        + +
        +    $ mount -t binfmt_misc none /proc/sys/fs/binfmt_misc
        +    $ echo ':llvm:M::llvm::/path/to/lli:' > /proc/sys/fs/binfmt_misc/register
        +    $ chmod u+x hello.bc                (if needed)
        +    $ ./hello.bc
        + 
        + +

        + This allows you to execute LLVM bytecode files directly. Thanks to Jack + Cummings for pointing this out! +

        + +
        + + + + + + +
        + +

        One useful source of information about the LLVM source base is the LLVM doxygen documentation available at http://llvm.cs.uiuc.edu/doxygen/. + The following is a brief introduction to code layout:

        + +
        + + + + +
        + +

        Every directory checked out of CVS will contain a CVS directory; for + the most part these can just be ignored.

        + +
        + + + + +
        + +

        This directory contains public header files exported from the LLVM + library. The three main subdirectories of this directory are:

        + +
          +
        1. llvm/include/llvm - This directory contains all of the LLVM + specific header files. This directory also has subdirectories for + different portions of LLVM: Analysis, CodeGen, + Target, Transforms, etc...
        2. + +
        3. llvm/include/Support - This directory contains generic + support libraries that are independent of LLVM, but are used by LLVM. + For example, some C++ STL utilities and a Command Line option processing + library store their header files here.
        4. + +
        5. llvm/include/Config - This directory contains header files + configured by the configure script. They wrap "standard" UNIX + and C header files. Source code can include these header files which + automatically take care of the conditional #includes that the + configure script generates.
        6. +
        + +
        + + +
        + llvm/lib +
        + +
        + +

        This directory contains most of the source files of the LLVM system. In LLVM, + almost all code exists in libraries, making it very easy to share code among the + different tools.

        + +
        +
        llvm/lib/VMCore/
        This directory holds the core LLVM + source files that implement core classes like Instruction and BasicBlock. + +
        llvm/lib/AsmParser/
        This directory holds the source code + for the LLVM assembly language parser library. + +
        llvm/lib/ByteCode/
        This directory holds code for reading + and write LLVM bytecode. + +
        llvm/lib/CWriter/
        This directory implements the LLVM to C + converter. + +
        llvm/lib/Analysis/
        This directory contains a variety of + different program analyses, such as Dominator Information, Call Graphs, + Induction Variables, Interval Identification, Natural Loop Identification, + etc... + +
        llvm/lib/Transforms/
        This directory contains the source + code for the LLVM to LLVM program transformations, such as Aggressive Dead + Code Elimination, Sparse Conditional Constant Propagation, Inlining, Loop + Invariant Code Motion, Dead Global Elimination, and many others... + +
        llvm/lib/Target/
        This directory contains files that + describe various target architectures for code generation. For example, + the llvm/lib/Target/SparcV9 directory holds the Sparc machine + description.
        + +
        llvm/lib/CodeGen/
        This directory contains the major parts + of the code generator: Instruction Selector, Instruction Scheduling, and + Register Allocation. + +
        llvm/lib/Support/
        This directory contains the source code + that corresponds to the header files located in + llvm/include/Support/. +
        + +
        + + + + +
        + +

        This directory contains libraries which are compiled into LLVM bytecode and + used when linking programs with the GCC front end. Most of these libraries are + skeleton versions of real libraries; for example, libc is a stripped down + version of glibc.

        + +

        Unlike the rest of the LLVM suite, this directory needs the LLVM GCC front + end to compile.

        + +
        + + +
        + llvm/test +
        + +
        + +

        This directory contains regression tests and source code that is used to test + the LLVM infrastructure.

        + +
        + + + + +
        + +

        The tools directory contains the executables built out of the + libraries above, which form the main part of the user interface. You can + always get help for a tool by typing tool_name --help. The + following is a brief introduction to the most important tools:

        + +
        +
        analyze
        analyze is used to run a specific + analysis on an input LLVM bytecode file and print out the results. It is + primarily useful for debugging analyses, or familiarizing yourself with + what an analysis does.

        + +

        bugpoint
        bugpoint is used to debug + optimization passes or code generation backends by narrowing down the + given test case to the minimum number of passes and/or instructions that + still cause a problem, whether it is a crash or miscompilation. See HowToSubmitABug.html for more information + on using bugpoint.

        + +

        llvm-ar
        The archiver produces an archive containing + the given LLVM bytecode files, optionally with an index for faster + lookup.

        + +

        llvm-as
        The assembler transforms the human readable + LLVM assembly to LLVM bytecode.

        + +

        llvm-dis
        The disassembler transforms the LLVM + bytecode to human readable LLVM assembly.

        + +

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

        + +

        lli
        lli is the LLVM interpreter, which + can directly execute LLVM bytecode (although very slowly...). In addition + to a simple interpreter, lli also has a tracing mode (entered by + specifying -trace on the command line). Finally, for + architectures that support it (currently only x86 and Sparc), by default, + lli will function as a Just-In-Time compiler (if the + 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, 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 + works just like any other GCC compiler, taking the typical -c, -S, -E, + -o options that are typically used. The source code for the + llvmgcc tool is currently not included in the LLVM CVS tree + because it is quite large and not very interesting.

        + +

        +
        +
        gccas
        This tool is invoked by the + llvmgcc frontend as the "assembler" part of the compiler. This + tool actually assembles LLVM assembly to LLVM bytecode, + performs a variety of optimizations, and outputs LLVM bytecode. Thus + when you invoke llvmgcc -c x.c -o x.o, you are causing + gccas to be run, which writes the x.o file (which is + an LLVM bytecode file that can be disassembled or manipulated just like + any other bytecode file). The command line interface to gccas + is designed to be as close as possible to the system + `as' utility so that the gcc frontend itself did not have to be + modified to interface to a "weird" assembler.

        + +

        gccld
        gccld links together several LLVM + bytecode files into one bytecode file and does some optimization. It is + the linker invoked by the GCC frontend when multiple .o files need to be + linked together. Like gccas, the command line interface of + gccld is designed to match the system linker, to aid + interfacing with the GCC frontend.

        +

        + +
        opt
        opt reads LLVM bytecode, applies a + series of LLVM to LLVM transformations (which are specified on the command + line), and then outputs the resultant bytecode. The 'opt --help' + command is a good way to get a list of the program transformations + available in LLVM. + +
        + +
        + + + + +
        + +

        This directory contains utilities for working with LLVM source code, and some + of the utilities are actually required as part of the build process because they + are code generators for parts of LLVM infrastructure.

        + +
        +
        Burg/
        Burg is an instruction selector + generator -- it builds trees on which it then performs pattern-matching to + select instructions according to the patterns the user has specified. Burg + is currently used in the Sparc V9 backend.

        + +

        codegen-diff
        codegen-diff is a script + that finds differences between code that LLC generates and code that LLI + generates. This is a useful tool if you are debugging one of them, + assuming that the other generates correct output. For the full user + manual, run `perldoc codegen-diff'.

        + +

        cvsupdate
        cvsupdate is a script that will + update your CVS tree, but produce a much cleaner and more organized output + than simply running `cvs -z3 up -dP' will. For example, it will group + together all the new and updated files and modified files in separate + sections, so you can see at a glance what has changed. If you are at the + top of your LLVM CVS tree, running utils/cvsupdate is the + preferred way of updating the tree.

        + +

        emacs/
        The emacs directory contains + syntax-highlighting files which will work with Emacs and XEmacs editors, + providing syntax highlighting support for LLVM assembly files and TableGen + description files. For information on how to use the syntax files, consult + the README file in that directory.

        + +

        getsrcs.sh
        The getsrcs.sh script finds + and outputs all non-generated source files, which is useful if one wishes + to do a lot of development across directories and does not want to + individually find each file. One way to use it is to run, for example: + xemacs `utils/getsources.sh` from the top of your LLVM source + tree.

        + +

        makellvm
        The makellvm script compiles all + files in the current directory and then compiles and links the tool that + is the first argument. For example, assuming you are in the directory + llvm/lib/Target/Sparc, if makellvm is in your path, + simply running makellvm llc will make a build of the current + directory, switch to directory llvm/tools/llc and build it, + causing a re-linking of LLC.

        + +

        NightlyTest.pl and + NightlyTestTemplate.html
        These files are used in a + cron script to generate nightly status reports of the functionality of + tools, and the results can be seen by following the appropriate link on + the LLVM homepage.

        + +

        TableGen/
        The TableGen directory contains + the tool used to generate register descriptions, instruction set + descriptions, and even assemblers from common TableGen description + files.

        + +

        vim/
        The vim directory contains + syntax-highlighting files which will work with the VIM editor, providing + syntax highlighting support for LLVM assembly files and TableGen + description files. For information on how to use the syntax files, consult + the README file in that directory.

        + +

        + +
        + + + + + +
        + +
          +
        1. First, create a simple C file, name it 'hello.c': +
          +    #include <stdio.h>
          +    int main() {
          +      printf("hello world\n");
          +      return 0;
          +    }
          +        
        2. + +
        3. Next, compile the C file into a LLVM bytecode file:

          +

          % llvmgcc hello.c -o hello

          + +

          Note that you should have already built the tools and they have to be + in your path, at least gccas and gccld.

          + +

          This will create two result files: hello and + hello.bc. The hello.bc is the LLVM bytecode that + corresponds the the compiled program and the library facilities that it + required. hello is a simple shell script that runs the bytecode + file with lli, making the result directly executable. Note that + all LLVM optimizations are enabled by default, so there is no need for a + "-O3" switch.

        4. + +
        5. Run the program. To make sure the program ran, execute one of the + following commands:

          + +

          % ./hello

          + +

          or

          + +

          % lli hello.bc

        6. + +
        7. Use the llvm-dis utility to take a look at the LLVM assembly + code:

          + +

          % llvm-dis < hello.bc | less

        8. + +
        9. Compile the program to native assembly using the LLC code + generator:

          + +

          % llc hello.bc -o hello.s

          + +
        10. Assemble the native assembly language file into a program:

          + +

          Solaris:% /opt/SUNWspro/bin/cc -xarch=v9 hello.s -o hello.native

          +

          Others:% gcc hello.s -o hello.native

          + +
        11. Execute the native code program:

          + +

          % ./hello.native

        12. + +
        + +
        + + + + + +
        + +

        If you are having problems building or using LLVM, or if you have any other + general questions about LLVM, please consult the Frequently + Asked Questions page.

        + +
        + + +
        + Links +
        + + +
        + +

        This document is just an introduction to how to use LLVM to do + some simple things... there are many more interesting and complicated things + that you can do that aren't documented here (but we'll gladly accept a patch + if you want to write something up!). For more information about LLVM, check + out:

        + + + +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
        + The LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + + + Index: llvm-www/releases/1.3/docs/HowToSubmitABug.html diff -c /dev/null llvm-www/releases/1.3/docs/HowToSubmitABug.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/HowToSubmitABug.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,360 ---- + + + + How to submit an LLVM bug report + + + + +
        + How to submit an LLVM bug report +
        + + + + + + +
        + +
          +
        1. Introduction - Got bugs?
        2. +
        3. Crashing Bugs +
        4. +
        5. Miscompilations
        6. +
        7. Incorrect code generation (JIT and LLC)
        8. + +
        + +
        +

        Written by Chris Lattner and + Misha Brukman

        +
        + +
        + Debugging +
        + + + + + +
        + +

        If you're working with LLVM and run into a bug, we definitely want to know + about it. This document describes what you can do to increase the odds of + getting it fixed quickly.

        + +

        Basically you have to do two things at a minimum. First, decide whether the + bug crashes the compiler (or an LLVM pass), or if the + compiler is miscompiling the program. Based on + what type of bug it is, follow the instructions in the linked section to narrow + down the bug so that the person who fixes it will be able to find the problem + more easily.

        + +

        Once you have a reduced test-case, go to the LLVM Bug Tracking + System, select the category in which the bug falls, and fill out the form + with the necessary details. The bug description should contain the following + information:

        + +
          +
        • All information necessary to reproduce the problem.
        • +
        • The reduced test-case that triggers the bug.
        • +
        • The location where you obtained LLVM (if not from our CVS + repository).
        • +
        + +

        Thanks for helping us make LLVM better!

        + +
        + + + + + +
        + +

        More often than not, bugs in the compiler cause it to crash - often due to an + assertion failure of some sort. If you are running opt or + analyze directly, and something crashes, jump to the section on + bugs in LLVM passes. Otherwise, the most important + piece of the puzzle is to figure out if it is the GCC-based front-end that is + buggy or if it's one of the LLVM tools that has problems.

        + +

        To figure out which program is crashing (the front-end, + gccas, or gccld), run the + llvm-gcc command line as you were when the crash occurred, but + add a -v option to the command line. The compiler will print out a + bunch of stuff, and should end with telling you that one of + cc1/cc1plus, gccas, or + gccld crashed.

        + +
          + +
        • If cc1 or cc1plus crashed, you found a + problem with the front-end. + Jump ahead to the section on front-end bugs.
        • + +
        • If gccas crashed, you found a bug in one + of the passes in gccas.
        • + +
        • If gccld crashed, you found a bug in one + of the passes in gccld.
        • + +
        • Otherwise, something really weird happened. Email the list with what you + have at this point.
        • + +
        + +
        + + + + +
        + +

        If the problem is in the front-end, you should re-run the same + llvm-gcc command that resulted in the crash, but add the + -save-temps option. The compiler will crash again, but it will leave + behind a foo.i file (containing preprocessed C source code) and + possibly foo.s (containing LLVM assembly code), for each + compiled foo.c file. Send us the foo.i file, + along with a brief description of the error it caused.

        + +
        + + + + +
        + +

        If you find that a bug crashes in the gccas stage of + compilation, compile your test-case to a .s file with the + -save-temps option to llvm-gcc. Then run:

        + +
        +

        gccas -debug-pass=Arguments < /dev/null -o - > /dev/null

        +
        + +

        ... which will print a list of arguments, indicating the list of passes that + gccas runs. Once you have the input file and the list of + passes, go to the section on debugging bugs in LLVM + passes.

        + +
        + + + + +
        + +

        If you find that a bug crashes in the gccld stage of + compilation, gather all of the .o bytecode files and libraries that are + being linked together (the "llvm-gcc -v" output should include + the full list of objects linked). Then run:

        + +
        +

        llvm-as < /dev/null > null.bc
        + gccld -debug-pass=Arguments null.bc
        +

        +
        + +

        ... which will print a list of arguments, indicating the list of passes that + gccld runs. Once you have the input files and the list of + passes, go to the section on debugging bugs in LLVM + passes.

        + +
        + + + + +
        + +

        At this point, you should have some number of LLVM assembly files or bytecode + files and a list of passes which crash when run on the specified input. In + order to reduce the list of passes (which is probably large) and the input to + something tractable, use the bugpoint tool as follows:

        + +
        +

        bugpoint <input files> <list of passes>

        +
        + +

        bugpoint will print a bunch of output as it reduces the + test-case, but it should eventually print something like this:

        + +
        +

        + ...
        + Emitted bytecode to 'bugpoint-reduced-simplified.bc'
        +
        + *** You can reproduce the problem with: opt bugpoint-reduced-simplified.bc -licm
        +

        +
        + +

        Once you complete this, please send the LLVM bytecode file and the command + line to reproduce the problem to the llvmbugs mailing list.

        + +
        + + + + + +
        + +

        A miscompilation occurs when a pass does not correctly transform a program, + thus producing errors that are only noticed during execution. This is different + from producing invalid LLVM code (i.e., code not in SSA form, using values + before defining them, etc.) which the verifier will check for after a pass + finishes its run.

        + +

        If it looks like the LLVM compiler is miscompiling a program, the very first + thing to check is to make sure it is not using undefined behavior. In + particular, check to see if the program valgrinds clean, passes purify, or some + other memory checker tool. Many of the "LLVM bugs" that we have chased down + ended up being bugs in the program being compiled, not LLVM.

        + +

        Once you determine that the program itself is not buggy, you should choose + which code generator you wish to compile the program with (e.g. C backend, the + JIT, or LLC) and optionally a series of LLVM passes to run. For example:

        + +
        +

        + bugpoint -run-cbe [... optzn passes ...] file-to-test.bc --args -- [program arguments]

        +
        + +

        bugpoint will try to narrow down your list of passes to the one pass + that causes an error, and simplify the bytecode file as much as it can to assist + you. It will print a message letting you know how to reproduce the resulting + error.

        + +
        + + + + + +
        + +

        Similarly to debugging incorrect compilation by mis-behaving passes, you can + debug incorrect code generation by either LLC or the JIT, using + bugpoint. The process bugpoint follows in this case is to try + to narrow the code down to a function that is miscompiled by one or the other + method, but since for correctness, the entire program must be run, + bugpoint will compile the code it deems to not be affected with the C + Backend, and then link in the shared object it generates.

        + +

        To debug the JIT:

        + +
        +
        + bugpoint -run-jit -output=[correct output file] [bytecode file]  \
        +          --tool-args -- [arguments to pass to lli]               \
        +          --args -- [program arguments]
        + 
        +
        + +

        Similarly, to debug the LLC, one would run:

        + +
        +
        + bugpoint -run-llc -output=[correct output file] [bytecode file]  \
        +          --tool-args -- [arguments to pass to llc]               \
        +          --args -- [program arguments]
        + 
        +
        + +

        Special note: if you are debugging MultiSource or SPEC tests that + already exist in the llvm/test hierarchy, there is an easier way to + debug the JIT, LLC, and CBE, using the pre-written Makefile targets, which + will pass the program options specified in the Makefiles:

        + +
        +

        + cd llvm/test/../../program
        + make bugpoint-jit +

        +
        + +

        At the end of a successful bugpoint run, you will be presented + with two bytecode files: a safe file which can be compiled with the C + backend and the test file which either LLC or the JIT + mis-codegenerates, and thus causes the error.

        + +

        To reproduce the error that bugpoint found, it is sufficient to do + the following:

        + +
          + +
        1. Regenerate the shared object from the safe bytecode file:

          + +
          +

          + llc -march=c safe.bc -o safe.c
          + gcc -shared safe.c -o safe.so +

          +
        2. + +
        3. If debugging LLC, compile test bytecode native and link with the shared + object:

          + +
          +

          + llc test.bc -o test.s -f
          + gcc test.s safe.so -o test.llc
          + ./test.llc [program options] +

          +
        4. + +
        5. If debugging the JIT, load the shared object and supply the test + bytecode:

          + +
          +

          lli -load=safe.so test.bc [program options]

          +
        6. + +
        + +
        + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
        + The LLVM Compiler Infrastructure +
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + + + Index: llvm-www/releases/1.3/docs/index.html diff -c /dev/null llvm-www/releases/1.3/docs/index.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/index.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,200 ---- + + + + Documentation for the LLVM System + + + + +
        Documentation for the LLVM System
        + + + +
        +

        Written by The LLVM Team

        +
        + + + + + + + + + + + + + + + + + + + + + + + + +
          + +
        • Writing an LLVM Pass - Information + on how to write LLVM transformations and analyses.
        • + +
        • The LLVM Target-Independent Code + Generator - The design and implementation of the LLVM code generator. + Useful if you are working on retargetting LLVM to a new architecture, designing + a new codegen pass, or enhancing existing components.
        • + +
        • TableGen Fundamentals - + Describes the TableGen tool, which is used heavily by the LLVM code + generator.
        • + +
        • Alias Analysis in LLVM - Information + on how to write a new alias analysis implementation or how to use existing + analyses.
        • + +
        • The Stacker Cronicles - This document + describes both the Stacker language and LLVM frontend, but also some details + about LLVM useful for those writing front-ends.
        • + +
        • Accurate Garbage Collection with + LLVM - The interfaces source-language compilers should use for compiling + GC'd programs.
        • + +
        • Source Level Debugging with + LLVM - This document describes the design and philosophy behind the LLVM + source-level debugger.
        • + +
        • Bugpoint automatic bug finder and + test-case reducer description and usage information.
        • + +
        + + + + + +
          +
        • The + LLVM Announcements List: This is a low volume list that provides important + announcements regarding LLVM. It gets email about once a month.
        • + +
        • The Developer's + List: This list is for people who want to be included in technical + discussions of LLVM. People post to this list when they have questions about + writing code for or using the LLVM tools. It is relatively low volume.
        • + +
        • The Bugs & + Patches Archive: This list gets emailed every time a bug is opened and + closed, and when people submit patches to be included in LLVM. It is higher + volume than the LLVMdev list.
        • + +
        • The CVS Commits + Archive: This list contains all commit messages that are made when LLVM + developers commit code changes to the CVS archive. It is useful for those who + want to stay on the bleeding edge of LLVM development. This list is very high + volume.
        • + +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + Index: llvm-www/releases/1.3/docs/LangRef.html diff -c /dev/null llvm-www/releases/1.3/docs/LangRef.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/LangRef.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,2599 ---- + + + + LLVM Assembly Language Reference Manual + + + + + +
        LLVM Language Reference Manual
        +
          +
        1. Abstract
        2. +
        3. Introduction
        4. +
        5. Identifiers
        6. +
        7. Type System +
            +
          1. Primitive Types +
              +
            1. Type Classifications
            2. +
            +
          2. +
          3. Derived Types +
              +
            1. Array Type
            2. +
            3. Function Type
            4. +
            5. Pointer Type
            6. +
            7. Structure Type
            8. + +
            +
          4. +
          +
        8. +
        9. High Level Structure +
            +
          1. Module Structure
          2. +
          3. Global Variables
          4. +
          5. Function Structure
          6. +
          +
        10. +
        11. Instruction Reference +
            +
          1. Terminator Instructions +
              +
            1. 'ret' Instruction
            2. +
            3. 'br' Instruction
            4. +
            5. 'switch' Instruction
            6. +
            7. 'invoke' Instruction
            8. +
            9. 'unwind' Instruction
            10. +
            +
          2. +
          3. Binary Operations +
              +
            1. 'add' Instruction
            2. +
            3. 'sub' Instruction
            4. +
            5. 'mul' Instruction
            6. +
            7. 'div' Instruction
            8. +
            9. 'rem' Instruction
            10. +
            11. 'setcc' Instructions
            12. +
            +
          4. +
          5. Bitwise Binary Operations +
              +
            1. 'and' Instruction
            2. +
            3. 'or' Instruction
            4. +
            5. 'xor' Instruction
            6. +
            7. 'shl' Instruction
            8. +
            9. 'shr' Instruction
            10. +
            +
          6. +
          7. Memory Access Operations +
              +
            1. 'malloc' Instruction
            2. +
            3. 'free' Instruction
            4. +
            5. 'alloca' Instruction
            6. +
            7. 'load' Instruction
            8. +
            9. 'store' Instruction
            10. +
            11. 'getelementptr' Instruction
            12. +
            +
          8. +
          9. Other Operations +
              +
            1. 'phi' Instruction
            2. +
            3. 'cast .. to' Instruction
            4. +
            5. 'select' Instruction
            6. +
            7. 'call' Instruction
            8. +
            9. 'vanext' Instruction
            10. +
            11. 'vaarg' Instruction
            12. +
            +
          10. +
          +
        12. +
        13. Intrinsic Functions +
            +
          1. Variable Argument Handling Intrinsics +
              +
            1. 'llvm.va_start' Intrinsic
            2. +
            3. 'llvm.va_end' Intrinsic
            4. +
            5. 'llvm.va_copy' Intrinsic
            6. +
            +
          2. +
          3. Accurate Garbage Collection Intrinsics +
              +
            1. 'llvm.gcroot' Intrinsic
            2. +
            3. 'llvm.gcread' Intrinsic
            4. +
            5. 'llvm.gcwrite' Intrinsic
            6. +
            +
          4. +
          5. Code Generator Intrinsics +
              +
            1. 'llvm.returnaddress' Intrinsic
            2. +
            3. 'llvm.frameaddress' Intrinsic
            4. +
            +
          6. +
          7. Operating System Intrinsics +
              +
            1. 'llvm.readport' Intrinsic
            2. +
            3. 'llvm.writeport' Intrinsic
            4. +
            5. 'llvm.readio' Intrinsic
            6. +
            7. 'llvm.writeio' Intrinsic
            8. +
            +
          8. Standard C Library Intrinsics +
              +
            1. 'llvm.memcpy' Intrinsic
            2. +
            3. 'llvm.memmove' Intrinsic
            4. +
            5. 'llvm.memset' Intrinsic
            6. +
            7. 'llvm.isunordered' Intrinsic
            8. +
            +
          9. +
          10. Debugger intrinsics
          11. +
          +
        14. +
        + +
        +

        Written by Chris Lattner + and Vikram Adve

        +
        + + + + + +
        +

        This document is a reference manual for the LLVM assembly language. + LLVM is an SSA based representation that provides type safety, + low-level operations, flexibility, and the capability of representing + 'all' high-level languages cleanly. It is the common code + representation used throughout all phases of the LLVM compilation + strategy.

        +
        + + + + + +
        + +

        The LLVM code representation is designed to be used in three + different forms: as an in-memory compiler IR, as an on-disk bytecode + representation (suitable for fast loading by a Just-In-Time compiler), + and as a human readable assembly language representation. This allows + LLVM to provide a powerful intermediate representation for efficient + compiler transformations and analysis, while providing a natural means + to debug and visualize the transformations. The three different forms + of LLVM are all equivalent. This document describes the human readable + representation and notation.

        + +

        The LLVM representation aims to be a light-weight and low-level + while being expressive, typed, and extensible at the same time. It + aims to be a "universal IR" of sorts, by being at a low enough level + that high-level ideas may be cleanly mapped to it (similar to how + microprocessors are "universal IR's", allowing many source languages to + be mapped to them). By providing type information, LLVM can be used as + the target of optimizations: for example, through pointer analysis, it + can be proven that a C automatic variable is never accessed outside of + the current function... allowing it to be promoted to a simple SSA + value instead of a memory location.

        + +
        + + + + +
        + +

        It is important to note that this document describes 'well formed' + LLVM assembly language. There is a difference between what the parser + accepts and what is considered 'well formed'. For example, the + following instruction is syntactically okay, but not well formed:

        + +
        +   %x = add int 1, %x
        + 
        + +

        ...because the definition of %x does not dominate all of + its uses. The LLVM infrastructure provides a verification pass that may + be used to verify that an LLVM module is well formed. This pass is + automatically run by the parser after parsing input assembly, and by + the optimizer before it outputs bytecode. The violations pointed out + by the verifier pass indicate bugs in transformation passes or input to + the parser.

        + +
        + + + + + +
        + +

        LLVM uses three different forms of identifiers, for different + purposes:

        + +
          +
        1. Numeric constants are represented as you would expect: 12, -3 + 123.421, etc. Floating point constants have an optional hexadecimal + notation.
        2. +
        3. Named values are represented as a string of characters with a '%' + prefix. For example, %foo, %DivisionByZero, + %a.really.long.identifier. The actual regular expression used is '%[a-zA-Z$._][a-zA-Z$._0-9]*'. + Identifiers which require other characters in their names can be + surrounded with quotes. In this way, anything except a " + character can be used in a name.
        4. +
        5. Unnamed values are represented as an unsigned numeric value with + a '%' prefix. For example, %12, %2, %44.
        6. +
        +

        LLVM requires that values start with a '%' sign for two reasons: + Compilers don't need to worry about name clashes with reserved words, + and the set of reserved words may be expanded in the future without + penalty. Additionally, unnamed identifiers allow a compiler to quickly + come up with a temporary variable without having to avoid symbol table + conflicts.

        +

        Reserved words in LLVM are very similar to reserved words in other + languages. There are keywords for different opcodes ('add', 'cast', 'ret', etc...), for primitive type names ('void', 'uint', + etc...), and others. These reserved words cannot conflict with + variable names, because none of them start with a '%' character.

        +

        Here is an example of LLVM code to multiply the integer variable '%X' + by 8:

        +

        The easy way:

        +
          %result = mul uint %X, 8
        +

        After strength reduction:

        +
          %result = shl uint %X, ubyte 3
        +

        And the hard way:

        +
          add uint %X, %X           ; yields {uint}:%0
        +   add uint %0, %0           ; yields {uint}:%1
        +   %result = add uint %1, %1
        +

        This last way of multiplying %X by 8 illustrates several + important lexical features of LLVM:

        +
          +
        1. Comments are delimited with a ';' and go until the end + of line.
        2. +
        3. Unnamed temporaries are created when the result of a computation + is not assigned to a named value.
        4. +
        5. Unnamed temporaries are numbered sequentially
        6. +
        +

        ...and it also show a convention that we follow in this document. + When demonstrating instructions, we will follow an instruction with a + comment that defines the type and name of value produced. Comments are + shown in italic text.

        +

        The one non-intuitive notation for constants is the optional + hexidecimal form of floating point constants. For example, the form 'double + 0x432ff973cafa8000' is equivalent to (but harder to read than) 'double + 4.5e+15' which is also supported by the parser. The only time + hexadecimal floating point constants are useful (and the only time that + they are generated by the disassembler) is when an FP constant has to + be emitted that is not representable as a decimal floating point number + exactly. For example, NaN's, infinities, and other special cases are + represented in their IEEE hexadecimal format so that assembly and + disassembly do not cause any bits to change in the constants.

        +
        + + + +
        +

        The LLVM type system is one of the most important features of the + intermediate representation. Being typed enables a number of + optimizations to be performed on the IR directly, without having to do + extra analyses on the side before the transformation. A strong type + system makes it easier to read the generated code and enables novel + analyses and transformations that are not feasible to perform on normal + three address code representations.

        +
        + + +
        +

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

        + + + + + + + + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        voidNo value
        ubyteUnsigned 8 bit value
        ushortUnsigned 16 bit value
        uintUnsigned 32 bit value
        ulongUnsigned 64 bit value
        float32 bit floating point value
        labelBranch destination
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        boolTrue or False value
        sbyteSigned 8 bit value
        shortSigned 16 bit value
        intSigned 32 bit value
        longSigned 64 bit value
        double64 bit floating point value
        +
        + +
        + + +
        +

        These different primitive types fall into a few useful + classifications:

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        signedsbyte, short, int, long, float, double
        unsignedubyte, ushort, uint, ulong
        integerubyte, sbyte, ushort, short, uint, int, ulong, long
        integralbool, ubyte, sbyte, ushort, short, uint, int, ulong, long
        floating pointfloat, double
        first classbool, ubyte, sbyte, ushort, short,
        + uint, int, ulong, long, float, double, pointer
        + +

        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 + instructions. This means that all structures and arrays must be + manipulated either by pointer or by component.

        +
        + + +
        +

        The real power in LLVM comes from the derived types in the system. + This is what allows a programmer to represent arrays, functions, + pointers, and other useful types. Note that these derived types may be + recursive: For example, it is possible to have a two dimensional array.

        +
        + + +
        +
        Overview:
        +

        The array type is a very simple derived type that arranges elements + sequentially in memory. The array type requires a size (number of + elements) and an underlying data type.

        +
        Syntax:
        +
          [<# elements> x <elementtype>]
        +

        The number of elements is a constant integer value, elementtype may + be any type with a size.

        +
        Examples:
        +

        [40 x int ]: Array of 40 integer values.
        + [41 x int ]: Array of 41 integer values.
        + [40 x uint]: Array of 40 unsigned integer values.

        +

        +

        Here are some examples of multidimensional arrays:

        + + + + + + + + + + + + + + + + +
        [3 x [4 x int]]: 3x4 array integer values.
        [12 x [10 x float]]: 12x10 array of single precision floating point values.
        [2 x [3 x [4 x uint]]]: 2x3x4 array of unsigned integer values.
        + +
        + + +
        +
        Overview:
        +

        The function type can be thought of as a function signature. It + consists of a return type and a list of formal parameter types. + Function types are usually used to build virtual function tables + (which are structures of pointers to functions), for indirect function + calls, and when defining a function.

        +

        + The return type of a function type cannot be an aggregate type. +

        +
        Syntax:
        +
          <returntype> (<parameter list>)
        +

        Where '<parameter list>' is a comma-separated list of + type specifiers. Optionally, the parameter list may include a type ..., + which indicates that the function takes a variable number of arguments. + Variable argument functions can access their arguments with the variable argument handling intrinsic functions.

        +
        Examples:
        + + + + + + + + + + + + + + + + +
        int (int): function taking an int, returning an int
        float (int, int *) *: Pointer to a function that takes + an int and a pointer to int, + returning float.
        int (sbyte *, ...): A vararg function that takes at least one pointer to sbyte (signed char in C), + which returns an integer. This is the signature for printf + in LLVM.
        + +
        + + +
        +
        Overview:
        +

        The structure type is used to represent a collection of data members + together in memory. The packing of the field types is defined to match + the ABI of the underlying processor. The elements of a structure may + be any type that has a size.

        +

        Structures are accessed using 'load + and 'store' by getting a pointer to a + field with the 'getelementptr' + instruction.

        +
        Syntax:
        +
          { <type list> }
        +
        Examples:
        + + + + + + + + + + + + +
        { int, int, int }: a triple of three int values
        { float, int (int) * }: A pair, where the first element is a float and the + second element is a pointer to a function that takes an int, returning + an int.
        + +
        + + +
        +
        Overview:
        +

        As in many languages, the pointer type represents a pointer or + reference to another object, which must live in memory.

        +
        Syntax:
        +
          <type> *
        +
        Examples:
        + + + + + + + + + + + + +
        [4x int]*: pointer to array + of four int values
        int (int *) *: A pointer to a function that takes an int, returning + an int.
        + +
        + + + + +
        +

        LLVM programs are composed of "Module"s, each of which is a + translation unit of the input programs. Each module consists of + functions, global variables, and symbol table entries. Modules may be + combined together with the LLVM linker, which merges function (and + global variable) definitions, resolves forward declarations, and merges + symbol table entries. Here is an example of the "hello world" module:

        +
        ; Declare the string constant as a global constant...
        + %.LC0 = internal constant [13 x sbyte] c"hello world\0A\00"          ; [13 x sbyte]*
        + 
        + ; External declaration of the puts function
        + declare int %puts(sbyte*)                                            ; int(sbyte*)* 
        + 
        + ; Definition of main function
        + int %main() {                                                        ; int()* 
        +         ; Convert [13x sbyte]* to sbyte *...
        +         %cast210 = getelementptr [13 x sbyte]* %.LC0, long 0, long 0 ; sbyte*
        + 
        +         ; Call puts function to write out the string to stdout...
        +         call int %puts(sbyte* %cast210)                              ; int
        +         ret int 0
        }
        +

        This example is made up of a global variable + named ".LC0", an external declaration of the "puts" + function, and a function definition + for "main".

        + In general, a module is made up of a list of global + values, where both functions and global variables are global values. + Global values are represented by a pointer to a memory location (in + this case, a pointer to an array of char, and a pointer to a function), + and have one of the following linkage types: +

        +
        +
        internal
        +
        Global values with internal linkage are only directly accessible + by objects in the current module. In particular, linking code into a + module with an internal global value may cause the internal to be + renamed as necessary to avoid collisions. Because the symbol is + internal to the module, all references can be updated. This + corresponds to the notion of the 'static' keyword in C, or the + idea of "anonymous namespaces" in C++. +

        +
        +
        linkonce:
        +
        "linkonce" linkage is similar to internal + linkage, with the twist that linking together two modules defining the + same linkonce globals will cause one of the globals to be + discarded. This is typically used to implement inline functions. + Unreferenced linkonce globals are allowed to be discarded. +

        +
        +
        weak:
        +
        "weak" linkage is exactly the same as linkonce + linkage, except that unreferenced weak globals may not be + discarded. This is used to implement constructs in C such as "int + X;" at global scope. +

        +
        +
        appending:
        +
        "appending" linkage may only be applied to global + variables of pointer to array type. When two global variables with + appending linkage are linked together, the two global arrays are + appended together. This is the LLVM, typesafe, equivalent of having + the system linker append together "sections" with identical names when + .o files are linked. +

        +
        +
        externally visible:
        +
        If none of the above identifiers are used, the global is + externally visible, meaning that it participates in linkage and can be + used to resolve external symbol references. +

        +
        +
        +

        +

        For example, since the ".LC0" + variable is defined to be internal, if another module defined a ".LC0" + variable and was linked with this one, one of the two would be renamed, + preventing a collision. Since "main" and "puts" are + external (i.e., lacking any linkage declarations), they are accessible + outside of the current module. It is illegal for a function declaration + to have any linkage type other than "externally visible".

        +
        + + + + +
        + +

        Global variables define regions of memory allocated at compilation + time instead of run-time. Global variables may optionally be + initialized. A variable may be defined as a global "constant", which + indicates that the contents of the variable will never be modified + (opening options for optimization).

        + +

        As SSA values, global variables define pointer values that are in + scope (i.e. they dominate) for all basic blocks in the program. Global + variables always define a pointer to their "content" type because they + describe a region of memory, and all memory objects in LLVM are + accessed through pointers.

        + +
        + + + +
        + Functions +
        + +
        + +

        LLVM function definitions are composed of a (possibly empty) argument list, + an opening curly brace, a list of basic blocks, and a closing curly brace. LLVM + function declarations are defined with the "declare" keyword, a + function name, and a function signature.

        + +

        A function definition contains a list of basic blocks, forming the CFG for + the function. Each basic block may optionally start with a label (giving the + basic block a symbol table entry), contains a list of instructions, and ends + with a terminator instruction (such as a branch or + function return).

        + +

        The first basic block in program is special in two ways: it is immediately + executed on entrance to the function, and it is not allowed to have predecessor + basic blocks (i.e. there can not be any branches to the entry block of a + function). Because the block can have no predecessors, it also cannot have any + PHI nodes.

        + +

        LLVM functions are identified by their name and type signature. Hence, two + functions with the same name but different parameter lists or return values are + considered different functions, and LLVM will resolves references to each + appropriately.

        + +
        + + + + + +
        +

        The LLVM instruction set consists of several different + classifications of instructions: terminator + instructions, binary instructions, memory instructions, and other + instructions.

        +
        + + +
        +

        As mentioned previously, every + basic block in a program ends with a "Terminator" instruction, which + indicates which block should be executed after the current block is + finished. These terminator instructions typically yield a 'void' + value: they produce control flow, not values (the one exception being + the 'invoke' instruction).

        +

        There are five different terminator instructions: the 'ret' instruction, the 'br' + instruction, the 'switch' instruction, + the 'invoke' instruction, and the 'unwind' instruction.

        +
        + + +
        +
        Syntax:
        +
          ret <type> <value>       ; Return a value from a non-void function
        +   ret void                 ; Return from void function
        + 
        +
        Overview:
        +

        The 'ret' instruction is used to return control flow (and a + value) from a function, back to the caller.

        +

        There are two forms of the 'ret' instruction: one that + returns a value and then causes control flow, and one that just causes + control flow to occur.

        +
        Arguments:
        +

        The 'ret' instruction may return any 'first class' type. Notice that a function is + not well formed if there exists a 'ret' + instruction inside of the function that returns a value that does not + match the return type of the function.

        +
        Semantics:
        +

        When the 'ret' instruction is executed, control flow + returns back to the calling function's context. If the caller is a "call" instruction, execution continues at + the instruction after the call. If the caller was an "invoke" instruction, execution continues + at the beginning "normal" of the destination block. If the instruction + returns a value, that value shall set the call or invoke instruction's + return value.

        +
        Example:
        +
          ret int 5                       ; Return an integer value of 5
        +   ret void                        ; Return from a void function
        + 
        +
        + + +
        +
        Syntax:
        +
          br bool <cond>, label <iftrue>, label <iffalse>
        br label <dest> ; Unconditional branch +
        +
        Overview:
        +

        The 'br' instruction is used to cause control flow to + transfer to a different basic block in the current function. There are + two forms of this instruction, corresponding to a conditional branch + and an unconditional branch.

        +
        Arguments:
        +

        The conditional branch form of the 'br' instruction takes a + single 'bool' value and two 'label' values. The + unconditional form of the 'br' instruction takes a single 'label' + value as a target.

        +
        Semantics:
        +

        Upon execution of a conditional 'br' instruction, the 'bool' + argument is evaluated. If the value is true, control flows + to the 'iftrue' label argument. If "cond" is false, + control flows to the 'iffalse' label argument.

        +
        Example:
        +
        Test:
        %cond = seteq int %a, %b
        br bool %cond, label %IfEqual, label %IfUnequal
        IfEqual:
        ret int 1
        IfUnequal:
        ret int 0
        +
        + + + +
        +
        Syntax:
        + +
        +   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' + instruction, allowing a branch to occur to one of many possible + destinations.

        + + +
        Arguments:
        + +

        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, control flow is + transfered to the corresponding destination; otherwise, control flow is + transfered to the default destination.

        + +
        Implementation:
        + +

        Depending on properties of the target machine and the particular + switch instruction, this instruction may be code generated in different + ways. For example, it could be generated 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 ]
        + 
        +
        + + +
        +
        Syntax:
        +
          <result> = invoke <ptr to function ty> %<function ptr val>(<function args>)
        to label <normal label> except label <exception label>
        +
        Overview:
        +

        The 'invoke' instruction causes control to transfer to a + specified function, with the possibility of control flow transfer to + either the 'normal' label label or the 'exception'label. + If the callee function returns with the "ret" + instruction, control flow will return to the "normal" label. If the + callee (or any indirect callees) returns with the "unwind" + instruction, control is interrupted, and continued at the dynamically + nearest "except" label.

        +
        Arguments:
        +

        This instruction requires several arguments:

        +
          +
        1. 'ptr to function ty': shall be the signature of the + pointer to function value being invoked. In most cases, this is a + direct function invocation, but indirect invokes are just as + possible, branching off an arbitrary pointer to function value.
        2. +
        3. 'function ptr val': An LLVM value containing a pointer + to a function to be invoked.
        4. +
        5. 'function args': argument list whose types match the + function signature argument types. If the function signature indicates + the function accepts a variable number of arguments, the extra + arguments can be specified.
        6. +
        7. 'normal label': the label reached when the called + function executes a 'ret' instruction.
        8. +
        9. 'exception label': the label reached when a callee + returns with the unwind instruction.
        10. +
        +
        Semantics:
        +

        This instruction is designed to operate as a standard 'call' instruction in most regards. The + primary difference is that it establishes an association with a label, + which is used by the runtime library to unwind the stack.

        +

        This instruction is used in languages with destructors to ensure + that proper cleanup is performed in the case of either a longjmp + or a thrown exception. Additionally, this is important for + implementation of 'catch' clauses in high-level languages that + support them.

        +
        Example:
        +
          %retval = invoke int %Test(int 15)
        to label %Continue
        except label %TestCleanup ; {int}:retval set +
        +
        + + +
        +
        Syntax:
        +
          unwind
        +
        Overview:
        +

        The 'unwind' instruction unwinds the stack, continuing + control flow at the first callee in the dynamic call stack which used + an invoke instruction to perform the + call. This is primarily used to implement exception handling.

        +
        Semantics:
        +

        The 'unwind' intrinsic causes execution of the current + function to immediately halt. The dynamic call stack is then searched + for the first invoke instruction on + the call stack. Once found, execution continues at the "exceptional" + destination block specified by the invoke instruction. If + there is no invoke instruction in the dynamic call chain, + undefined behavior results.

        +
        + + +
        +

        Binary operators are used to do most of the computation in a + program. They require two operands, execute an operation on them, and + produce a single value. The result value of a binary operator is not + necessarily the same type as its operands.

        +

        There are several different binary operators:

        +
        + + +
        +
        Syntax:
        +
          <result> = add <ty> <var1>, <var2>   ; yields {ty}:result
        + 
        +
        Overview:
        +

        The 'add' instruction returns the sum of its two operands.

        +
        Arguments:
        +

        The two arguments to the 'add' instruction must be either integer or floating point + values. Both arguments must have identical types.

        +
        Semantics:
        +

        The value produced is the integer or floating point sum of the two + operands.

        +
        Example:
        +
          <result> = add int 4, %var          ; yields {int}:result = 4 + %var
        + 
        +
        + + +
        +
        Syntax:
        +
          <result> = sub <ty> <var1>, <var2>   ; yields {ty}:result
        + 
        +
        Overview:
        +

        The 'sub' instruction returns the difference of its two + operands.

        +

        Note that the 'sub' instruction is used to represent the 'neg' + instruction present in most other intermediate representations.

        +
        Arguments:
        +

        The two arguments to the 'sub' instruction must be either integer or floating point + values. Both arguments must have identical types.

        +
        Semantics:
        +

        The value produced is the integer or floating point difference of + the two operands.

        +
        Example:
        +
          <result> = sub int 4, %var          ; yields {int}:result = 4 - %var
        +   <result> = sub int 0, %val          ; yields {int}:result = -%var
        + 
        +
        + + +
        +
        Syntax:
        +
          <result> = mul <ty> <var1>, <var2>   ; yields {ty}:result
        + 
        +
        Overview:
        +

        The 'mul' instruction returns the product of its two + operands.

        +
        Arguments:
        +

        The two arguments to the 'mul' instruction must be either integer or floating point + values. Both arguments must have identical types.

        +
        Semantics:
        +

        The value produced is the integer or floating point product of the + two operands.

        +

        There is no signed vs unsigned multiplication. The appropriate + action is taken based on the type of the operand.

        +
        Example:
        +
          <result> = mul int 4, %var          ; yields {int}:result = 4 * %var
        + 
        +
        + + +
        +
        Syntax:
        +
          <result> = div <ty> <var1>, <var2>   ; yields {ty}:result
        + 
        +
        Overview:
        +

        The 'div' instruction returns the quotient of its two + operands.

        +
        Arguments:
        +

        The two arguments to the 'div' instruction must be either integer or floating point + values. Both arguments must have identical types.

        +
        Semantics:
        +

        The value produced is the integer or floating point quotient of the + two operands.

        +
        Example:
        +
          <result> = div int 4, %var          ; yields {int}:result = 4 / %var
        + 
        +
        + + +
        +
        Syntax:
        +
          <result> = rem <ty> <var1>, <var2>   ; yields {ty}:result
        + 
        +
        Overview:
        +

        The 'rem' instruction returns the remainder from the + division of its two operands.

        +
        Arguments:
        +

        The two arguments to the 'rem' instruction must be either integer or floating point + values. Both arguments must have identical types.

        +
        Semantics:
        +

        This returns the remainder of a division (where the result + has the same sign as the divisor), not the modulus (where the + result has the same sign as the dividend) of a value. For more + information about the difference, see: The + Math Forum.

        +
        Example:
        +
          <result> = rem int 4, %var          ; yields {int}:result = 4 % %var
        + 
        +
        + + +
        +
        Syntax:
        +
          <result> = seteq <ty> <var1>, <var2>   ; yields {bool}:result
        +   <result> = setne <ty> <var1>, <var2>   ; yields {bool}:result
        +   <result> = setlt <ty> <var1>, <var2>   ; yields {bool}:result
        +   <result> = setgt <ty> <var1>, <var2>   ; yields {bool}:result
        +   <result> = setle <ty> <var1>, <var2>   ; yields {bool}:result
        +   <result> = setge <ty> <var1>, <var2>   ; yields {bool}:result
        + 
        +
        Overview:
        +

        The 'setcc' family of instructions returns a boolean + value based on a comparison of their two operands.

        +
        Arguments:
        +

        The two arguments to the 'setcc' instructions must + be of first class type (it is not possible + to compare 'label's, 'array's, 'structure' + or 'void' values, etc...). Both arguments must have identical + types.

        +
        Semantics:
        +

        The 'seteq' instruction yields a true 'bool' + value if both operands are equal.
        + The 'setne' instruction yields a true 'bool' + value if both operands are unequal.
        + The 'setlt' instruction yields a true 'bool' + value if the first operand is less than the second operand.
        + The 'setgt' instruction yields a true 'bool' + value if the first operand is greater than the second operand.
        + The 'setle' instruction yields a true 'bool' + value if the first operand is less than or equal to the second operand.
        + The 'setge' instruction yields a true 'bool' + value if the first operand is greater than or equal to the second + operand.

        +
        Example:
        +
          <result> = seteq int   4, 5        ; yields {bool}:result = false
        +   <result> = setne float 4, 5        ; yields {bool}:result = true
        +   <result> = setlt uint  4, 5        ; yields {bool}:result = true
        +   <result> = setgt sbyte 4, 5        ; yields {bool}:result = false
        +   <result> = setle sbyte 4, 5        ; yields {bool}:result = true
        +   <result> = setge sbyte 4, 5        ; yields {bool}:result = false
        + 
        +
        + + +
        +

        Bitwise binary operators are used to do various forms of + bit-twiddling in a program. They are generally very efficient + instructions, and can commonly be strength reduced from other + instructions. They require two operands, execute an operation on them, + and produce a single value. The resulting value of the bitwise binary + operators is always the same type as its first operand.

        +
        + + +
        +
        Syntax:
        +
          <result> = and <ty> <var1>, <var2>   ; yields {ty}:result
        + 
        +
        Overview:
        +

        The 'and' instruction returns the bitwise logical and of + its two operands.

        +
        Arguments:
        +

        The two arguments to the 'and' instruction must be integral values. Both arguments must have + identical types.

        +
        Semantics:
        +

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

        +

        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        In0In1Out
        000
        010
        100
        111
        +
        +
        Example:
        +
          <result> = and int 4, %var         ; yields {int}:result = 4 & %var
        +   <result> = and int 15, 40          ; yields {int}:result = 8
        +   <result> = and int 4, 8            ; yields {int}:result = 0
        + 
        +
        + + +
        +
        Syntax:
        +
          <result> = or <ty> <var1>, <var2>   ; yields {ty}:result
        + 
        +
        Overview:
        +

        The 'or' instruction returns the bitwise logical inclusive + or of its two operands.

        +
        Arguments:
        +

        The two arguments to the 'or' instruction must be integral values. Both arguments must have + identical types.

        +
        Semantics:
        +

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

        +

        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        In0In1Out
        000
        011
        101
        111
        +
        +
        Example:
        +
          <result> = or int 4, %var         ; yields {int}:result = 4 | %var
        +   <result> = or int 15, 40          ; yields {int}:result = 47
        +   <result> = or int 4, 8            ; yields {int}:result = 12
        + 
        +
        + + +
        +
        Syntax:
        +
          <result> = xor <ty> <var1>, <var2>   ; yields {ty}:result
        + 
        +
        Overview:
        +

        The 'xor' instruction returns the bitwise logical exclusive + or of its two operands. The xor is used to implement the + "one's complement" operation, which is the "~" operator in C.

        +
        Arguments:
        +

        The two arguments to the 'xor' instruction must be integral values. Both arguments must have + identical types.

        +
        Semantics:
        +

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

        +

        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        In0In1Out
        000
        011
        101
        110
        +
        +

        +
        Example:
        +
          <result> = xor int 4, %var         ; yields {int}:result = 4 ^ %var
        +   <result> = xor int 15, 40          ; yields {int}:result = 39
        +   <result> = xor int 4, 8            ; yields {int}:result = 12
        +   <result> = xor int %V, -1          ; yields {int}:result = ~%V
        + 
        +
        + + +
        +
        Syntax:
        +
          <result> = shl <ty> <var1>, ubyte <var2>   ; yields {ty}:result
        + 
        +
        Overview:
        +

        The 'shl' instruction returns the first operand shifted to + the left a specified number of bits.

        +
        Arguments:
        +

        The first argument to the 'shl' instruction must be an integer type. The second argument must be an 'ubyte' + type.

        +
        Semantics:
        +

        The value produced is var1 * 2var2.

        +
        Example:
        +
          <result> = shl int 4, ubyte %var   ; yields {int}:result = 4 << %var
        +   <result> = shl int 4, ubyte 2      ; yields {int}:result = 16
        +   <result> = shl int 1, ubyte 10     ; yields {int}:result = 1024
        + 
        +
        + + +
        +
        Syntax:
        +
          <result> = shr <ty> <var1>, ubyte <var2>   ; yields {ty}:result
        + 
        +
        Overview:
        +

        The 'shr' instruction returns the first operand shifted to + the right a specified number of bits.

        +
        Arguments:
        +

        The first argument to the 'shr' instruction must be an integer type. The second argument must be an 'ubyte' + type.

        +
        Semantics:
        +

        If the first argument is a signed type, the + most significant bit is duplicated in the newly free'd bit positions. + If the first argument is unsigned, zero bits shall fill the empty + positions.

        +
        Example:
        +
          <result> = shr int 4, ubyte %var   ; yields {int}:result = 4 >> %var
        +   <result> = shr uint 4, ubyte 1     ; yields {uint}:result = 2
        +   <result> = shr int 4, ubyte 2      ; yields {int}:result = 1
        +   <result> = shr sbyte 4, ubyte 3    ; yields {sbyte}:result = 0
        +   <result> = shr sbyte -2, ubyte 1   ; yields {sbyte}:result = -1
        + 
        +
        + + +
        +

        A key design point of an SSA-based representation is how it + represents memory. In LLVM, no memory locations are in SSA form, which + makes things very simple. This section describes how to read, write, + allocate and free memory in LLVM.

        +
        + + +
        +
        Syntax:
        +
          <result> = malloc <type>, uint <NumElements>     ; yields {type*}:result
        +   <result> = malloc <type>                         ; yields {type*}:result
        + 
        +
        Overview:
        +

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

        +
        Arguments:
        +

        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.

        +

        'type' must be a sized type.

        +
        Semantics:
        +

        Memory is allocated using the system "malloc" function, and + a pointer is returned.

        +
        Example:
        +
          %array  = malloc [4 x ubyte ]                    ; yields {[%4 x ubyte]*}:array
        + 
        +   %size   = add uint 2, 2                          ; yields {uint}:size = uint 4
        +   %array1 = malloc ubyte, uint 4                   ; yields {ubyte*}:array1
        +   %array2 = malloc [12 x ubyte], uint %size        ; yields {[12 x ubyte]*}:array2
        + 
        +
        + + +
        +
        Syntax:
        +
          free <type> <value>                              ; yields {void}
        + 
        +
        Overview:
        +

        The 'free' instruction returns memory back to the unused + memory heap, to be reallocated in the future.

        +

        +
        Arguments:
        +

        'value' shall be a pointer value that points to a value + that was allocated with the 'malloc' + instruction.

        +
        Semantics:
        +

        Access to the memory pointed to by the pointer is not longer defined + after this instruction executes.

        +
        Example:
        +
          %array  = malloc [4 x ubyte]                    ; yields {[4 x ubyte]*}:array
        +             free   [4 x ubyte]* %array
        + 
        +
        + + +
        +
        Syntax:
        +
          <result> = alloca <type>, uint <NumElements>  ; yields {type*}:result
        +   <result> = alloca <type>                      ; yields {type*}:result
        + 
        +
        Overview:
        +

        The 'alloca' instruction allocates memory on the current + stack frame of the procedure that is live until the current function + returns to its caller.

        +
        Arguments:
        +

        The the 'alloca' instruction allocates sizeof(<type>)*NumElements + bytes of memory on the runtime stack, returning a pointer of the + appropriate type to the program. The second form of the instruction is + a shorter version of the first that defaults to allocating one element.

        +

        'type' may be any sized type.

        +
        Semantics:
        +

        Memory is allocated, a pointer is returned. 'alloca'd + memory is automatically released when the function returns. The 'alloca' + instruction is commonly used to represent automatic variables that must + have an address available. When the function returns (either with the ret or invoke + instructions), the memory is reclaimed.

        +
        Example:
        +
          %ptr = alloca int                              ; yields {int*}:ptr
        +   %ptr = alloca int, uint 4                      ; yields {int*}:ptr
        + 
        +
        + + +
        +
        Syntax:
        +
          <result> = load <ty>* <pointer>
        <result> = volatile load <ty>* <pointer>
        +
        Overview:
        +

        The 'load' instruction is used to read from memory.

        +
        Arguments:
        +

        The argument to the 'load' instruction specifies the memory + address to load from. The pointer must point to a first class type. If the load is + marked as volatile then the optimizer is not allowed to modify + the number or order of execution of this load with other + volatile load and store + instructions.

        +
        Semantics:
        +

        The location of memory pointed to is loaded.

        +
        Examples:
        +
          %ptr = alloca int                               ; yields {int*}:ptr
        +   store int 3, int* %ptr                          ; yields {void}
        +   %val = load int* %ptr                           ; yields {int}:val = int 3
        + 
        +
        + + +
        Syntax:
        +
          store <ty> <value>, <ty>* <pointer>                   ; yields {void}
        +   volatile store <ty> <value>, <ty>* <pointer>                   ; yields {void}
        + 
        +
        Overview:
        +

        The 'store' instruction is used to write to memory.

        +
        Arguments:
        +

        There are two arguments to the 'store' instruction: a value + to store and an address to store it into. The type of the '<pointer>' + operand must be a pointer to the type of the '<value>' + operand. If the store is marked as volatile then the + optimizer is not allowed to modify the number or order of execution of + this store with other volatile load and store instructions.

        +
        Semantics:
        +

        The contents of memory are updated to contain '<value>' + at the location specified by the '<pointer>' operand.

        +
        Example:
        +
          %ptr = alloca int                               ; yields {int*}:ptr
        +   store int 3, int* %ptr                          ; yields {void}
        +   %val = load int* %ptr                           ; yields {int}:val = int 3
        + 
        + + + +
        +
        Syntax:
        +
        +   <result> = getelementptr <ty>* <ptrval>{, <ty> <idx>}*
        + 
        + +
        Overview:
        + +

        + The 'getelementptr' instruction is used to get the address of a + subelement of an aggregate data structure.

        + +
        Arguments:
        + +

        This instruction takes a list of integer constants that indicate what + elements of the aggregate object to index to. The actual types of the arguments + provided depend on the type of the first pointer argument. The + 'getelementptr' instruction is used to index down through the type + levels of a structure. When indexing into a structure, only uint + integer constants are allowed. When indexing into an array or pointer + int and long indexes are allowed of any sign.

        + +

        For example, let's consider a C code fragment and how it gets + compiled to LLVM:

        + +
        +   struct RT {
        +     char A;
        +     int B[10][20];
        +     char C;
        +   };
        +   struct ST {
        +     int X;
        +     double Y;
        +     struct RT Z;
        +   };
        + 
        +   int *foo(struct ST *s) {
        +     return &s[1].Z.B[5][13];
        +   }
        + 
        + +

        The LLVM code generated by the GCC frontend is:

        + +
        +   %RT = type { sbyte, [10 x [20 x int]], sbyte }
        +   %ST = type { int, double, %RT }
        + 
        +   implementation
        + 
        +   int* %foo(%ST* %s) {
        +   entry:
        +     %reg = getelementptr %ST* %s, int 1, uint 2, uint 1, int 5, int 13
        +     ret int* %reg
        +   }
        + 
        + +
        Semantics:
        + +

        The index types specified for the 'getelementptr' instruction depend + on the pointer type that is being index into. Pointer + and array types require uint, int, + ulong, or long values, and structure + types require uint constants.

        + +

        In the example above, the first index is indexing into the '%ST*' + type, which is a pointer, yielding a '%ST' = '{ int, double, %RT + }' type, a structure. The second index indexes into the third element of + the structure, yielding a '%RT' = '{ sbyte, [10 x [20 x int]], + sbyte }' type, another structure. The third index indexes into the second + element of the structure, yielding a '[10 x [20 x int]]' type, an + array. The two dimensions of the array are subscripted into, yielding an + 'int' type. The 'getelementptr' instruction return a pointer + to this element, thus computing a value of 'int*' type.

        + +

        Note that it is perfectly legal to index partially through a + structure, returning a pointer to an inner element. Because of this, + the LLVM code for the given testcase is equivalent to:

        + +
        +   int* "foo"(%ST* %s) {
        +     %t1 = getelementptr %ST* %s, int 1                        ; yields %ST*:%t1
        +     %t2 = getelementptr %ST* %t1, int 0, uint 2               ; yields %RT*:%t2
        +     %t3 = getelementptr %RT* %t2, int 0, uint 1               ; yields [10 x [20 x int]]*:%t3
        +     %t4 = getelementptr [10 x [20 x int]]* %t3, int 0, int 5  ; yields [20 x int]*:%t4
        +     %t5 = getelementptr [20 x int]* %t4, int 0, int 13        ; yields int*:%t5
        +     ret int* %t5
        +   }
        + 
        +
        Example:
        +
        +     ; yields [12 x ubyte]*:aptr
        +     %aptr = getelementptr {int, [12 x ubyte]}* %sptr, long 0, uint 1
        + 
        + +
        + + +
        +

        The instructions in this category are the "miscellaneous" + instructions, which defy better classification.

        +
        + + +
        +
        Syntax:
        +
          <result> = phi <ty> [ <val0>, <label0>], ...
        +
        Overview:
        +

        The 'phi' instruction is used to implement the φ node in + the SSA graph representing the function.

        +
        Arguments:
        +

        The type of the incoming values are specified with the first type + field. After this, the 'phi' instruction takes a list of pairs + as arguments, with one pair for each predecessor basic block of the + current block. Only values of first class + type may be used as the value arguments to the PHI node. Only labels + may be used as the label arguments.

        +

        There must be no non-phi instructions between the start of a basic + block and the PHI instructions: i.e. PHI instructions must be first in + a basic block.

        +
        Semantics:
        +

        At runtime, the 'phi' instruction logically takes on the + value specified by the parameter, depending on which basic block we + came from in the last terminator instruction.

        +
        Example:
        +
        Loop:       ; Infinite loop that counts from 0 on up...
        %indvar = phi uint [ 0, %LoopHeader ], [ %nextindvar, %Loop ]
        %nextindvar = add uint %indvar, 1
        br label %Loop
        +
        + + + + +
        + +
        Syntax:
        + +
        +   <result> = cast <ty> <value> to <ty2>             ; yields ty2
        + 
        + +
        Overview:
        + +

        + The 'cast' instruction is used as the primitive means to convert + integers to floating point, change data type sizes, and break type safety (by + casting pointers). +

        + + +
        Arguments:
        + +

        + The 'cast' instruction takes a value to cast, which must be a first + class value, and a type to cast it to, which must also be a first class type. +

        + +
        Semantics:
        + +

        + This instruction follows the C rules for explicit casts when determining how the + data being cast must change to fit in its new container. +

        + +

        + When casting to bool, any value that would be considered true in the context of + a C 'if' condition is converted to the boolean 'true' values, + all else are 'false'. +

        + +

        + When extending an integral value from a type of one signness to another (for + example 'sbyte' to 'ulong'), the value is sign-extended if the + source value is signed, and zero-extended if the source value is + unsigned. bool values are always zero extended into either zero or + one. +

        + +
        Example:
        + +
        +   %X = cast int 257 to ubyte              ; yields ubyte:1
        +   %Y = cast int 123 to bool               ; yields bool:true
        + 
        +
        + + + + +
        + +
        Syntax:
        + +
        +   <result> = select bool <cond>, <ty> <val1>, <ty> <val2>             ; yields ty
        + 
        + +
        Overview:
        + +

        + The 'select' instruction is used to choose one value based on a + condition, without branching. +

        + + +
        Arguments:
        + +

        + The 'select' instruction requires a boolean value indicating the condition, and two values of the same first class type. +

        + +
        Semantics:
        + +

        + If the boolean condition evaluates to true, the instruction returns the first + value argument, otherwise it returns the second value argument. +

        + +
        Example:
        + +
        +   %X = select bool true, ubyte 17, ubyte 42          ; yields ubyte:17
        + 
        +
        + + + + + + + +
        +
        Syntax:
        +
          <result> = call <ty>* <fnptrval>(<param list>)
        +
        Overview:
        +

        The 'call' instruction represents a simple function call.

        +
        Arguments:
        +

        This instruction requires several arguments:

        +
          +
        1. +

          'ty': shall be the signature of the pointer to function + value being invoked. The argument types must match the types implied + by this signature.

          +
        2. +
        3. +

          'fnptrval': An LLVM value containing a pointer to a + function to be invoked. In most cases, this is a direct function + invocation, but indirect calls are just as possible, + calling an arbitrary pointer to function values.

          +
        4. +
        5. +

          'function args': argument list whose types match the + function signature argument types. If the function signature + indicates the function accepts a variable number of arguments, the + extra arguments can be specified.

          +
        6. +
        +
        Semantics:
        +

        The 'call' instruction is used to cause control flow to + transfer to a specified function, with its incoming arguments bound to + the specified values. Upon a 'ret' + instruction in the called function, control flow continues with the + instruction after the function call, and the return value of the + function is bound to the result argument. This is a simpler case of + the invoke instruction.

        +
        Example:
        +
          %retval = call int %test(int %argc)
        call int(sbyte*, ...) *%printf(sbyte* %msg, int 12, sbyte 42);
        +
        + + +
        +
        Syntax:
        +
          <resultarglist> = vanext <va_list> <arglist>, <argty>
        +
        Overview:
        +

        The 'vanext' instruction is used to access arguments passed + through the "variable argument" area of a function call. It is used to + implement the va_arg macro in C.

        +
        Arguments:
        +

        This instruction takes a valist value and the type of the + argument. It returns another valist.

        +
        Semantics:
        +

        The 'vanext' instruction advances the specified valist + past an argument of the specified type. In conjunction with the vaarg instruction, it is used to implement + the va_arg macro available in C. For more information, see + the variable argument handling Intrinsic + Functions.

        +

        It is legal for this instruction to be called in a function which + does not take a variable number of arguments, for example, the vfprintf + function.

        +

        vanext is an LLVM instruction instead of an intrinsic function because it takes an type as + an argument.

        +
        Example:
        +

        See the variable argument processing + section.

        +
        + + +
        +
        Syntax:
        +
          <resultval> = vaarg <va_list> <arglist>, <argty>
        +
        Overview:
        +

        The 'vaarg' instruction is used to access arguments passed + through the "variable argument" area of a function call. It is used to + implement the va_arg macro in C.

        +
        Arguments:
        +

        This instruction takes a valist value and the type of the + argument. It returns a value of the specified argument type.

        +
        Semantics:
        +

        The 'vaarg' instruction loads an argument of the specified + type from the specified va_list. In conjunction with the vanext instruction, it is used to + implement the va_arg macro available in C. For more + information, see the variable argument handling Intrinsic + Functions.

        +

        It is legal for this instruction to be called in a function which + does not take a variable number of arguments, for example, the vfprintf + function.

        +

        vaarg is an LLVM instruction instead of an intrinsic function because it takes an type as + an argument.

        +
        Example:
        +

        See the variable argument processing + section.

        +
        + + + + + +
        + +

        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. +

        + +
        + + + + +
        + +

        Variable argument support is defined in LLVM with the vanext instruction and these three + intrinsic functions. These functions are related to the similarly + named macros defined in the <stdarg.h> header file.

        + +

        All of these functions operate on arguments that use a + target-specific value type "va_list". The LLVM assembly + language reference manual does not define what this type is, so all + transformations should be prepared to handle intrinsics with any type + used.

        + +

        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* %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
        + }
        + 
        +
        + + + + + +
        +
        Syntax:
        +
          call va_list ()* %llvm.va_start()
        +
        Overview:
        +

        The 'llvm.va_start' intrinsic returns a new <arglist> + for subsequent use by the variable argument intrinsics.

        +
        Semantics:
        +

        The 'llvm.va_start' intrinsic works just like the va_start + macro available in C. In a target-dependent way, it initializes and + returns a va_list element, so that the next vaarg + will produce the first variable argument passed to the function. Unlike + the C va_start macro, this intrinsic does not need to know the + last argument of the function, the compiler can figure that out.

        +

        Note that this intrinsic function is only legal to be called from + within the body of a variable argument function.

        +
        + + + + +
        +
        Syntax:
        +
          call void (va_list)* %llvm.va_end(va_list <arglist>)
        +
        Overview:
        +

        The 'llvm.va_end' intrinsic destroys <arglist> + which has been initialized previously with llvm.va_start + or llvm.va_copy.

        +
        Arguments:
        +

        The argument is a va_list to destroy.

        +
        Semantics:
        +

        The 'llvm.va_end' intrinsic works just like the va_end + macro available in C. In a target-dependent way, it destroys the va_list. + Calls to llvm.va_start and llvm.va_copy must be matched exactly + with calls to llvm.va_end.

        +
        + + + + +
        + +
        Syntax:
        + +
        +   call va_list (va_list)* %llvm.va_copy(va_list <destarglist>)
        + 
        + +
        Overview:
        + +

        The 'llvm.va_copy' intrinsic copies the current argument position + from the source argument list to the destination argument list.

        + +
        Arguments:
        + +

        The argument is the va_list to copy.

        + +
        Semantics:
        + +

        The 'llvm.va_copy' intrinsic works just like the va_copy + macro available in C. In a target-dependent way, it copies the source + va_list element into the returned list. This intrinsic is necessary + because the llvm.va_start intrinsic may be + arbitrarily complex and require memory allocation, for example.

        + +
        + + + + +
        + +

        + LLVM support for Accurate Garbage + Collection requires the implementation and generation of these intrinsics. + These intrinsics allow identification of GC roots on the + stack, as well as garbage collector implementations that require read and write barriers. + Front-ends for type-safe garbage collected languages should generate these + intrinsics to make use of the LLVM garbage collectors. For more details, see Accurate Garbage Collection with LLVM. +

        +
        + + + + +
        + +
        Syntax:
        + +
        +   call void (<ty>**, <ty2>*)* %llvm.gcroot(<ty>** %ptrloc, <ty2>* %metadata)
        + 
        + +
        Overview:
        + +

        The 'llvm.gcroot' intrinsic declares the existance of a GC root to + the code generator, and allows some metadata to be associated with it.

        + +
        Arguments:
        + +

        The first argument specifies the address of a stack object that contains the + root pointer. The second pointer (which must be either a constant or a global + value address) contains the meta-data to be associated with the root.

        + +
        Semantics:
        + +

        At runtime, a call to this intrinsics stores a null pointer into the "ptrloc" + location. At compile-time, the code generator generates information to allow + the runtime to find the pointer at GC safe points. +

        + +
        + + + + + +
        + +
        Syntax:
        + +
        +   call sbyte* (sbyte**)* %llvm.gcread(sbyte** %Ptr)
        + 
        + +
        Overview:
        + +

        The 'llvm.gcread' intrinsic identifies reads of references from heap + locations, allowing garbage collector implementations that require read + barriers.

        + +
        Arguments:
        + +

        The argument is the address to read from, which should be an address + allocated from the garbage collector.

        + +
        Semantics:
        + +

        The 'llvm.gcread' intrinsic has the same semantics as a load + instruction, but may be replaced with substantially more complex code by the + garbage collector runtime, as needed.

        + +
        + + + + + +
        + +
        Syntax:
        + +
        +   call void (sbyte*, sbyte**)* %llvm.gcwrite(sbyte* %P1, sbyte** %P2)
        + 
        + +
        Overview:
        + +

        The 'llvm.gcwrite' intrinsic identifies writes of references to heap + locations, allowing garbage collector implementations that require write + barriers (such as generational or reference counting collectors).

        + +
        Arguments:
        + +

        The first argument is the reference to store, and the second is the heap + location to store to.

        + +
        Semantics:
        + +

        The 'llvm.gcwrite' intrinsic has the same semantics as a store + instruction, but may be replaced with substantially more complex code by the + garbage collector runtime, as needed.

        + +
        + + + + + + +
        +

        + 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. +

        +
        + + + + +
        +

        + These intrinsics are provided by LLVM to support the implementation of + operating system level code. +

        + +
        + + + + +
        + +
        Syntax:
        +
        +   call <integer type> (<integer type>)* %llvm.readport (<integer type> <address>)
        + 
        + +
        Overview:
        + +

        + The 'llvm.readport' intrinsic reads data from the specified hardware + I/O port. +

        + +
        Arguments:
        + +

        + The argument to this intrinsic indicates the hardware I/O address from which + to read the data. The address is in the hardware I/O address namespace (as + opposed to being a memory location for memory mapped I/O). +

        + +
        Semantics:
        + +

        + The 'llvm.readport' intrinsic reads data from the hardware I/O port + specified by address and returns the value. The address and return + value must be integers, but the size is dependent upon the platform upon which + the program is code generated. For example, on x86, the address must be an + unsigned 16 bit value, and the return value must be 8, 16, or 32 bits. +

        + +
        + + + + +
        + +
        Syntax:
        +
        +   call void (<integer type>, <integer type>)* %llvm.writeport (<integer type> <value>, <integer type> <address>)
        + 
        + +
        Overview:
        + +

        + The 'llvm.writeport' intrinsic writes data to the specified hardware + I/O port. +

        + +
        Arguments:
        + +

        + The first argument is the value to write to the I/O port. +

        + +

        + The second argument indicates the hardware I/O address to which data should be + written. The address is in the hardware I/O address namespace (as opposed to + being a memory location for memory mapped I/O). +

        + +
        Semantics:
        + +

        + The 'llvm.writeport' intrinsic writes value to the I/O port + specified by address. The address and value must be integers, but the + size is dependent upon the platform upon which the program is code generated. + For example, on x86, the address must be an unsigned 16 bit value, and the + value written must be 8, 16, or 32 bits in length. +

        + +
        + + + + +
        + +
        Syntax:
        +
        +   call <result> (<ty>*)* %llvm.readio (<ty> * <pointer>)
        + 
        + +
        Overview:
        + +

        + The 'llvm.readio' intrinsic reads data from a memory mapped I/O + address. +

        + +
        Arguments:
        + +

        + The argument to this intrinsic is a pointer indicating the memory address from + which to read the data. The data must be a + first class type. +

        + +
        Semantics:
        + +

        + The 'llvm.readio' intrinsic reads data from a memory mapped I/O + location specified by pointer and returns the value. The argument must + be a pointer, and the return value must be a + first class type. However, certain architectures + may not support I/O on all first class types. For example, 32 bit processors + may only support I/O on data types that are 32 bits or less. +

        + +

        + This intrinsic enforces an in-order memory model for llvm.readio and + llvm.writeio calls on machines that use dynamic scheduling. Dynamically + scheduled processors may execute loads and stores out of order, re-ordering at + run time accesses to memory mapped I/O registers. Using these intrinsics + ensures that accesses to memory mapped I/O registers occur in program order. +

        + +
        + + + + +
        + +
        Syntax:
        +
        +   call void (<ty1>, <ty2>*)* %llvm.writeio (<ty1> <value>, <ty2> * <pointer>)
        + 
        + +
        Overview:
        + +

        + The 'llvm.writeio' intrinsic writes data to the specified memory + mapped I/O address. +

        + +
        Arguments:
        + +

        + The first argument is the value to write to the memory mapped I/O location. + The second argument is a pointer indicating the memory address to which the + data should be written. +

        + +
        Semantics:
        + +

        + The 'llvm.writeio' intrinsic writes value to the memory mapped + I/O address specified by pointer. The value must be a + first class type. However, certain architectures + may not support I/O on all first class types. For example, 32 bit processors + may only support I/O on data types that are 32 bits or less. +

        + +

        + This intrinsic enforces an in-order memory model for llvm.readio and + llvm.writeio calls on machines that use dynamic scheduling. Dynamically + scheduled processors may execute loads and stores out of order, re-ordering at + run time accesses to memory mapped I/O registers. Using these intrinsics + ensures that accesses to memory mapped I/O registers occur in program order. +

        + +
        + + + + +
        +

        + 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. +

        +
        + + + + + +
        + +
        Syntax:
        +
        +   call bool (<float or double>, <float or double>)* %llvm.isunordered(<float or double> Val1,
        +                                                                       <float or double> Val2)
        + 
        + +
        Overview:
        + +

        + The 'llvm.isunordered' intrinsic returns true if either or both of the + specified floating point values is a NAN. +

        + +
        Arguments:
        + +

        + The arguments are floating point numbers of the same type. +

        + +
        Semantics:
        + +

        + If either or both of the arguments is a SNAN or QNAN, it returns true, otherwise + false. +

        +
        + + + + + + + +
        +

        + The LLVM debugger intrinsics (which all start with llvm.dbg. prefix), + are described in the LLVM Source Level + Debugging document. +

        +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
        + The LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:03 $ +
        + + Index: llvm-www/releases/1.3/docs/LLVMVsTheWorld.html diff -c /dev/null llvm-www/releases/1.3/docs/LLVMVsTheWorld.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/LLVMVsTheWorld.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,180 ---- + + + + + LLVM vs. the World - Comparing Compilers to Compilers + + + + +
        + LLVM vs. the World - Comparing Compilers to Compilers +
        + +
          +
        1. Introduction
        2. +
        3. General Applicability
        4. +
        5. Type System
        6. +
        7. Control-flow and Data-flow Information
        8. +
        9. Registers
        10. +
        11. Programmer Interface
        12. +
        13. Machine Code Emission
        14. +
        + +
        +

        Written by Brian R. Gaeke

        +
        + + + + + +
        +

        Whether you are a stranger to LLVM or not, and whether you are considering + using it for your projects or not, you may find it useful to understand how we + compare ourselves to other well-known compilers. The following list of points + should help you understand -- from our point of view -- some of the important + ways in which we see LLVM as different from other selected compilers and + code generation systems.

        + +

        At the moment, we only compare ourselves below to GCC and GNU lightning, but we will try + to revise and expand it as our knowledge and experience permit. Contributions are + welcome.

        +
        + + + + + +
        +

        GNU lightning: Only currently usable for dynamic runtime emission of binary + machine code to memory. Supports one backend at a time.

        + +

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

        + +

        GCC: Many relatively mature platform backends support assembly-language code + generation from many source languages. No run-time compilation + support.

        +
        + + + + + +
        +

        GNU lightning: C integer types and "void *" are supported. No type checking + is performed. Explicit type casts are not typically necessary unless the + underlying machine-specific types are distinct (e.g., sign- or zero-extension is + apparently necessary, but casting "int" to "void *" would not be.) + Floating-point support may not work on all platforms (it does not appear to be + documented in the latest release).

        + +

        LLVM: Compositional type system based on C types, supporting structures, + opaque types, and C integer and floating point types. Explicit cast instructions + are required to transform a value from one type to another.

        + +

        GCC: Union of high-level types including those used in Pascal, C, C++, Ada, + Java, and FORTRAN.

        +
        + + + + + +
        +

        GNU lightning: No data-flow information encoded in the generated program. No + support for calculating CFG or def-use chains over generated programs.

        + +

        LLVM: Scalar values in Static Single-Assignment form; def-use chains and CFG + always implicitly available and automatically kept up to date.

        + +

        GCC: Trees and RTL do not directly encode data-flow info; but def-use chains + and CFGs can be calculated on the side. They are not automatically kept up to + date.

        +
        + + +
        + Registers +
        + + +
        +

        GNU lightning: Very small fixed register set -- it takes the least common + denominator of supported platforms; basically it inherits its tiny register set + from IA-32, unnecessarily crippling targets like PowerPC with a large register + set.

        + +

        LLVM: An infinite register set, reduced to a particular platform's finite + register set by register allocator.

        + +

        GCC: Trees and RTL provide an arbitrarily large set of values. Reduced to a + particular platform's finite register set by register allocator.

        +
        + + + + + +
        +

        GNU lightning: Library interface based on C preprocessor macros that emit + binary code for a particular instruction to memory. No support for manipulating + code before emission.

        + +

        LLVM: Library interface based on classes representing platform-independent + intermediate code (Instruction) and platform-dependent code (MachineInstr) which + can be manipulated arbitrarily and then emitted to memory.

        + +

        GCC: Internal header file interface (tree.h) to abstract syntax trees, + representing roughly the union of all possible supported source-language + constructs; also, an internal header file interface (rtl.h, rtl.def) to a + low-level IR called RTL which represents roughly the union of all possible + target machine instructions.

        +
        + + + + + +
        +

        GNU lightning: Only supports binary machine code emission to memory.

        + +

        LLVM: Supports writing out assembly language to a file, and binary machine + code to memory, from the same back-end.

        + +

        GCC: Supports writing out assembly language to a file. No support for + emitting machine code to memory.

        +
        + + + +
        + + + + Index: llvm-www/releases/1.3/docs/ObjectFiles.html diff -c /dev/null llvm-www/releases/1.3/docs/ObjectFiles.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/ObjectFiles.html Fri Aug 13 17:03:03 2004 *************** *** 0 **** --- 1,300 ---- + + + + Object Files: Understanding The Result Of LLVM Compilation + + + +
        Object Files: Understanding The Result Of LLVM Compilation
        +
        +
          +
        1. Abstract
        2. +
        3. Introduction
        4. +
        5. File Contents
        6. +
        7. Linkage Rules Of Thumb +
            +
          1. Always Link vmcore.o, support.a +
          2. Placeholder +
          +
        8. +
        + +
        +

        Written by Reid Spencer

        +
        + +
        + + + +
        +

        This document describes the contents of the many objects files and libraries + that are produced by compiling LLVM. To make use of LLVM this information is + needed in order to understand what files should be linked into your program. +

        +
        + + +
        +

        If you're writing a compiler, virtual machine, or any other utility for + LLVM, you'll need to figure out which of the many .a (archive) and .o + (object) files you will need to link with to be successful. An + understanding of the contents of these files and their inter-relationships + will be useful in coming up with an optimal specification for the objects + and libraries to link with. +

        +

        The purpose of this document is to hopefully reduce some of the trial and + error that the author experienced in using LLVM. +

        +
        + +
        File Contents
        +
        +

        The table below provides a summary of the basic contents of each file.

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Summary Of LLVM Library And Object Files +

        Library

        Description

        libipo.a + An archive of all inter-procedural optimizations. +
        libscalaropts.a + An archive of all scalar optimizations. +
        libtransforms.a + An archive of just the level raise pass. +
        libtarget.a + An archive containing code generator support for describing + target architectures. +
        libanalysis.a + An archive containing intra-procedural analyses. +
        libdatastructure.a + An archive containing optimizations for data structures. +
        libinstrument.aNo idea.
        libregalloc.aRegister Allocation code.
        libipa.a + An archive containing inter-procedural analyses
        libtransformutils.a + Utiltities for transformations? +
        libsupport.aGeneral support utilities
        libevar.aLive variable analysis for SPARC

        Object File

        Description

        support.oGeneral support utilities
        asmparser.oAssembler Parser
        bcreader.oByte Code Reader
        bcwriter.oByte Code Writer
        sched.oSPARC instruction scheduler
        selectiondag.oAggressive instruction selector for Directed Acyclic Graphs
        transformutils.oUtilities for code transformations
        ipa.oInter-Procedural Analysis Optimizations
        select.oSPARC instruction selector
        cwriter.o"C" Code Writer
        profpaths.oPath profiling instrumentation
        regalloc.oRegister Allocation
        instrument.oInstrumentation? Of What?
        datastructure.oData Structure Analysis
        codegen.oNative code generation
        livevar.oLive Variable Analysis
        vmcore.oVirtual Machine Core
        lli-interpreter.oInterpreter for LLVM ByteCode
        lli-jit.o + Just-In-Time Compiler For LLVM ByteCode +
        executionengine.oEngine for LLI
        debugger.oSource Level Debugging Support
        analysis.oGeneral Framework For Analysis?
        sparc.oSun SPARC Processor Specific
        target.oTarget Machine Support?
        transforms.oCode Transformations
        x86.oIntel x86 Processor Specific
        powerpc.oPowerPC Processor Specific
        scalaropts.oOptimizations For Scalars
        ipo.oInter-Procedural Optimization
        trace.oSupport For Tracing/Debugging?
        profile_rt.oRuntime Library For Profiler
        sample.oSample Program ?
        stkr_compiler.oStacker Language Compiler Library
        stkr_runtime.oStacker Language Runtime Library
        +
        +

        + + +
        +

        This section contains various "rules of thumb" about what files you + should link into your programs.

        +
        + + +
        +

        No matter what you do with LLVM, you'll always need to link with vmcore.o + and support.a.

        +
        + + +
        +

        Need more rules of thumb here.

        +
        + +
        + + + + Index: llvm-www/releases/1.3/docs/OpenProjects.html diff -c /dev/null llvm-www/releases/1.3/docs/OpenProjects.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/OpenProjects.html Fri Aug 13 17:03:04 2004 *************** *** 0 **** --- 1,360 ---- + + + + Open LLVM Projects + + + + +
        + Open LLVM Projects +
        + + + +
        +

        Written by the LLVM Team

        +
        + + + + + + +
        + +

        This document is meant to be a sort of "big TODO list" for LLVM. Each + project in this document is something that would be useful for LLVM to have, and + would also be a great way to get familiar with the system. Some of these + projects are small and self-contained, which may be implemented in a couple of + days, others are larger. Several of these projects may lead to interesting + research projects in their own right. In any case, we welcome all + contributions.

        + +

        If you are thinking about tackling one of these projects, please send a mail + to the LLVM + Developer's mailing list, so that we know the project is being worked on. + Additionally this is a good way to get more information about a specific project + or to suggest other projects to add to this page. +

        + +

        The projects in this page are open-ended. More specific projects are + filed as unassigned enhancements in the + LLVM bug tracker. See the list of currently outstanding issues if you wish to help improve LLVM.

        + +
        + + + + + +
        + +

        Improvements to the current infrastructure are always very welcome and tend + to be fairly straight-forward to implement. Here are some of the key areas that + can use improvement...

        + +
        + + + + +
        + +

        + The LLVM bug tracker occasionally + has "code-cleanup" bugs filed in it. Taking one of these and fixing it is a good + way to get your feet wet in the LLVM code and discover how some of its components + work. +

        + +
        + + + + +
        + +

        It would be very useful to port glibc to LLVM. This would allow a + variety of interprocedural algorithms to be much more effective in the face of + library calls. The most important pieces to port are things like the string + library and the stdio related functions... low-level system calls like + 'read' should stay unimplemented in LLVM.

        + +
        + + + + +
        + +

        We are always looking for new testcases and benchmarks for use with LLVM. In + particular, it is useful to try compiling your favorite C source code with LLVM. + If it doesn't compile, try to figure out why or report it to the llvm-bugs list. If you + get the program to compile, it would be extremely useful to convert the build + system to be compatible with the LLVM Programs testsuite so that we can check it + into CVS and the automated tester can use it to track progress of the + compiler.

        + +

        When testing a code, try running it with a variety of optimizations, and with + all the back-ends: CBE, llc, and lli.

        + +
        + + + + +
        + +
          +
        1. Add support for platform-independent prefetch support. The GCC prefetch project page + has a good survey of the prefetching capabilities of a variety of modern + processors.
        2. + +
        + +
        + + + + +
        + +
          +
        1. Someone needs to look into getting the ranlib tool to index LLVM + bytecode files, so that linking in .a files is not hideously slow. They + would also then have to implement the reader for this index in + gccld.
        2. + +
        3. Rework the PassManager to be more flexible
        4. + +
        5. Some transformations and analyses only work on reducible flow graphs. It + would be nice to have a transformation which could be "required" by these passes + which makes irreducible graphs reducible. This can easily be accomplished + through code duplication. See Making Graphs Reducible + with Controlled Node Splitting and perhaps Nesting of Reducible and + Irreducible Loops.
        6. + +
        + +
        + + + + + +
        + +

        Sometimes creating new things is more fun than improving existing things. + These projects tend to be more involved and perhaps require more work, but can + also be very rewarding.

        + +
        + + + + + +
        + +

        Many ideas for feature requests are stored in LLVM bugzilla. Just search for bugs with a "new-feature" keyword.

        + +
        + + + + +
        + +

        We have a strong base for development of + both pointer analysis based optimizations as well as pointer analyses + themselves. It seems natural to want to take advantage of this...

        + +
          +
        1. Implement a flow-sensitive context-sensitive alias analysis algorithm
          + - Pick one of the somewhat efficient algorithms, but strive for maximum + precision
        2. + +
        3. Implement a flow-sensitive context-insensitive alias analysis algorithm
          + - Just an efficient local algorithm perhaps?
        4. + +
        5. Implement alias-analysis-based optimizations: +
            +
          • Dead store elimination
          • +
          • ...
          • +
        6. +
        + +
        + + + + +
        + +

        We now have a unified infrastructure for writing profile-guided + transformations, which will work either at offline-compile-time or in the JIT, + but we don't have many transformations. We would welcome new profile-guided + transformations as well as improvements to the current profiling system. +

        + +

        Ideas for profile guided transformations:

        + +
          +
        1. Superblock formation (with many optimizations)
        2. +
        3. Loop unrolling/peeling
        4. +
        5. Profile directed inlining
        6. +
        7. Code layout
        8. +
        9. ...
        10. +
        + +

        Improvements to the existing support:

        + +
          +
        1. The current block and edge profiling code that gets inserted is very simple + and inefficient. Through the use of control-dependence information, many fewer + counters could be inserted into the code. Also, if the execution count of a + loop is known to be a compile-time or runtime constant, all of the counters in + the loop could be avoided.
        2. + +
        3. You could implement one of the "static profiling" algorithms which analyze a + piece of code an make educated guesses about the relative execution frequencies + of various parts of the code.
        4. + +
        5. You could add path profiling support, or adapt the existing LLVM path + profiling code to work with the generic profiling interfaces.
        6. +
        + +
        + + + + +
        + +
          +
        1. Implement a Dependence Analysis Infrastructure
          + - Design some way to represent and query dep analysis
        2. +
        3. Implement a strength reduction pass
        4. +
        5. Value range propagation pass
        6. +
        + +
        + + + + +
        + +
          +
        1. Implement a better instruction selector
        2. +
        3. Implement support for the "switch" instruction without requiring the + lower-switches pass.
        4. +
        5. Implement interprocedural register allocation. The CallGraphSCCPass can be + used to implement a bottom-up analysis that will determine the *actual* + registers clobbered by a function. Use the pass to fine tune register usage + in callers based on *actual* registers used by the callee.
        6. +
        + +
        + + + + +
        + +
          +
        1. Port the Bigloo + Scheme compiler, from Manuel Serrano at INRIA Sophia-Antipolis, to + output LLVM bytecode. It seems that it can already output .NET + bytecode, JVM bytecode, and C, so LLVM would ostensibly be another good + candidate.
        2. +
        3. Write a new frontend for C/C++ in C++, giving us the ability to + directly use LLVM C++ classes from within a compiler rather than use + C-based wrapper functions a la llvm-gcc. One possible starting point is the C++ + yacc grammar by Ed Willink.
        4. +
        5. Write a new frontend for some other language (Java? OCaml? Forth?)
        6. +
        7. Write a new backend for a target (IA64? MIPS? MMIX?)
        8. +
        9. Write a disassembler for machine code that would use TableGen to output + MachineInstrs for transformations, optimizations, etc.
        10. +
        11. Random test vector generator: Use a C grammar to generate random C code; + run it through llvm-gcc, then run a random set of passes on it using opt. + Try to crash opt. When opt crashes, use bugpoint to reduce the test case and + mail the result to yourself. Repeat ad infinitum.
        12. +
        13. Design a simple, recognizable logo.
        14. +
        + +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
        + LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:04 $ +
        + + + Index: llvm-www/releases/1.3/docs/ProgrammersManual.html diff -c /dev/null llvm-www/releases/1.3/docs/ProgrammersManual.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/ProgrammersManual.html Fri Aug 13 17:03:04 2004 *************** *** 0 **** --- 1,2053 ---- + + + + LLVM Programmer's Manual + + + + +
        + LLVM Programmer's Manual +
        + +
          +
        1. Introduction
        2. +
        3. General Information + +
        4. +
        5. Important and useful LLVM APIs + +
        6. +
        7. Helpful Hints for Common Operations + +
        8. +
        9. The Core LLVM Class Hierarchy Reference +
        + + + + + + + +
        + +

        This document is meant to highlight some of the important classes and + interfaces available in the LLVM source-base. This manual is not + intended to explain what LLVM is, how it works, and what LLVM code looks + like. It assumes that you know the basics of LLVM and are interested + in writing transformations or otherwise analyzing or manipulating the + code.

        + +

        This document should get you oriented so that you can find your + way in the continuously growing source code that makes up the LLVM + infrastructure. Note that this manual is not intended to serve as a + replacement for reading the source code, so if you think there should be + a method in one of these classes to do something, but it's not listed, + check the source. Links to the doxygen sources + are provided to make this as easy as possible.

        + +

        The first section of this document describes general information that is + useful to know when working in the LLVM infrastructure, and the second describes + the Core LLVM classes. In the future this manual will be extended with + information describing how to use extension libraries, such as dominator + information, CFG traversal routines, and useful utilities like the InstVisitor template.

        + +
        + + + + + +
        + +

        This section contains general information that is useful if you are working + in the LLVM source-base, but that isn't specific to any particular API.

        + +
        + + + + +
        + +

        LLVM makes heavy use of the C++ Standard Template Library (STL), + perhaps much more than you are used to, or have seen before. Because of + this, you might want to do a little background reading in the + techniques used and capabilities of the library. There are many good + pages that discuss the STL, and several books on the subject that you + can get, so it will not be discussed in this document.

        + +

        Here are some useful links:

        + +
          + +
        1. Dinkumware C++ Library + reference - an excellent reference for the STL and other parts of the + standard C++ library.
        2. + +
        3. C++ In a Nutshell - This is an + O'Reilly book in the making. It has a decent + Standard Library + Reference that rivals Dinkumware's, and is unfortunately no longer free since the book has been + published.
        4. + +
        5. C++ Frequently Asked + Questions
        6. + +
        7. SGI's STL Programmer's Guide - + Contains a useful Introduction to the + STL.
        8. + +
        9. Bjarne Stroustrup's C++ + Page
        10. + +
        11. + Bruce Eckel's Thinking in C++, 2nd ed. Volume 2 Revision 4.0 (even better, get + the book).
        12. + +
        + +

        You are also encouraged to take a look at the LLVM Coding Standards guide which focuses on how + to write maintainable code more than where to put your curly braces.

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

        Here we highlight some LLVM APIs that are generally useful and good to + know about when writing transformations.

        + +
        + + + + +
        + +

        The LLVM source-base makes extensive use of a custom form of RTTI. + These templates have many similarities to the C++ dynamic_cast<> + operator, but they don't have some drawbacks (primarily stemming from + the fact that dynamic_cast<> only works on classes that + have a v-table). Because they are used so often, you must know what they + do and how they work. All of these templates are defined in the Support/Casting.h + file (note that you very rarely have to include this file directly).

        + +
        +
        isa<>:
        + +
        The isa<> operator works exactly like the Java + "instanceof" operator. It returns true or false depending on whether + a reference or pointer points to an instance of the specified class. This can + be very useful for constraint checking of various sorts (example below).
        + +
        cast<>:
        + +
        The cast<> operator is a "checked cast" operation. It + converts a pointer or reference from a base class to a derived cast, causing + an assertion failure if it is not really an instance of the right type. This + should be used in cases where you have some information that makes you believe + that something is of the right type. An example of the isa<> + and cast<> template is: + +
        +   static bool isLoopInvariant(const Value *V, const Loop *L) {
        +     if (isa<Constant>(V) || isa<Argument>(V) || isa<GlobalValue>(V))
        +       return true;
        + 
        +   // Otherwise, it must be an instruction...
        +   return !L->contains(cast<Instruction>(V)->getParent());
        +   
        + +

        Note that you should not use an isa<> test followed + by a cast<>, for that use the dyn_cast<> + operator.

        + +
        + +
        dyn_cast<>:
        + +
        The dyn_cast<> operator is a "checking cast" operation. It + checks to see if the operand is of the specified type, and if so, returns a + pointer to it (this operator does not work with references). If the operand is + not of the correct type, a null pointer is returned. Thus, this works very + much like the dynamic_cast operator in C++, and should be used in the + same circumstances. Typically, the dyn_cast<> operator is used + in an if statement or some other flow control statement like this: + +
        +      if (AllocationInst *AI = dyn_cast<AllocationInst>(Val)) {
        +        ...
        +      }
        +    
        + +

        This form of the if statement effectively combines together a + call to isa<> and a call to cast<> into one + statement, which is very convenient.

        + +

        Another common example is:

        + +
        +      // Loop over all of the phi nodes in a basic block
        +      BasicBlock::iterator BBI = BB->begin();
        +      for (; PHINode *PN = dyn_cast<PHINode>(BBI); ++BBI)
        +        std::cerr << *PN;
        +    
        + +

        Note that the dyn_cast<> operator, like C++'s + dynamic_cast or Java's instanceof operator, can be abused. + In particular you should not use big chained if/then/else blocks to + check for lots of different variants of classes. If you find yourself + wanting to do this, it is much cleaner and more efficient to use the + InstVisitor class to dispatch over the instruction type directly.

        + +
        + +
        cast_or_null<>:
        + +
        The cast_or_null<> operator works just like the + cast<> operator, except that it allows for a null pointer as + an argument (which it then propagates). This can sometimes be useful, + allowing you to combine several null checks into one.
        + +
        dyn_cast_or_null<>:
        + +
        The dyn_cast_or_null<> operator works just like the + dyn_cast<> operator, except that it allows for a null pointer + as an argument (which it then propagates). This can sometimes be useful, + allowing you to combine several null checks into one.
        + +
        + +

        These five templates can be used with any classes, whether they have a + v-table or not. To add support for these templates, you simply need to add + classof static methods to the class you are interested casting + to. Describing this is currently outside the scope of this document, but there + are lots of examples in the LLVM source base.

        + +
        + + + + +
        + +

        Often when working on your pass you will put a bunch of debugging printouts + and other code into your pass. After you get it working, you want to remove + it... but you may need it again in the future (to work out new bugs that you run + across).

        + +

        Naturally, because of this, you don't want to delete the debug printouts, + but you don't want them to always be noisy. A standard compromise is to comment + them out, allowing you to enable them if you need them in the future.

        + +

        The "Support/Debug.h" + file provides a macro named DEBUG() that is a much nicer solution to + this problem. Basically, you can put arbitrary code into the argument of the + DEBUG macro, and it is only executed if 'opt' (or any other + tool) is run with the '-debug' command line argument:

        + +
             ... 
        DEBUG(std::cerr << "I am here!\n");
        ...
        + +

        Then you can run your pass like this:

        + +
          $ opt < a.bc > /dev/null -mypass
        <no output>
        $ opt < a.bc > /dev/null -mypass -debug
        I am here!
        $
        + +

        Using the DEBUG() macro instead of a home-brewed solution allows you + to not have to create "yet another" command line option for the debug output for + your pass. Note that DEBUG() macros are disabled for optimized builds, + so they do not cause a performance impact at all (for the same reason, they + should also not contain side-effects!).

        + +

        One additional nice thing about the DEBUG() macro is that you can + enable or disable it directly in gdb. Just use "set DebugFlag=0" or + "set DebugFlag=1" from the gdb if the program is running. If the + program hasn't been started yet, you can always just run it with + -debug.

        + +
        + + + + +
        + +

        Sometimes you may find yourself in a situation where enabling -debug + just turns on too much information (such as when working on the code + generator). If you want to enable debug information with more fine-grained + control, you define the DEBUG_TYPE macro and the -debug only + option as follows:

        + +
             ...
        DEBUG(std::cerr << "No debug type\n");
        #undef DEBUG_TYPE
        #define DEBUG_TYPE "foo"
        DEBUG(std::cerr << "'foo' debug type\n");
        #undef DEBUG_TYPE
        #define DEBUG_TYPE "bar"
        DEBUG(std::cerr << "'bar' debug type\n");
        #undef DEBUG_TYPE
        #define DEBUG_TYPE ""
        DEBUG(std::cerr << "No debug type (2)\n");
        ...
        + +

        Then you can run your pass like this:

        + +
          $ opt < a.bc > /dev/null -mypass
        <no output>
        $ opt < a.bc > /dev/null -mypass -debug
        No debug type
        'foo' debug type
        'bar' debug type
        No debug type (2)
        $ opt < a.bc > /dev/null -mypass -debug-only=foo
        'foo' debug type
        $ opt < a.bc > /dev/null -mypass -debug-only=bar
        'bar' debug type
        $
        + +

        Of course, in practice, you should only set DEBUG_TYPE at the top of + a file, to specify the debug type for the entire module (if you do this before + you #include "Support/Debug.h", you don't have to insert the ugly + #undef's). Also, you should use names more meaningful than "foo" and + "bar", because there is no system in place to ensure that names do not + conflict. If two different modules use the same string, they will all be turned + on when the name is specified. This allows, for example, all debug information + for instruction scheduling to be enabled with -debug-type=InstrSched, + even if the source lives in multiple files.

        + +
        + + + + +
        + +

        The "Support/Statistic.h" file + provides a template named Statistic that is used as a unified way to + keep track of what the LLVM compiler is doing and how effective various + optimizations are. It is useful to see what optimizations are contributing to + making a particular program run faster.

        + +

        Often you may run your pass on some big program, and you're interested to see + how many times it makes a certain transformation. Although you can do this with + hand inspection, or some ad-hoc method, this is a real pain and not very useful + for big programs. Using the Statistic template makes it very easy to + keep track of this information, and the calculated information is presented in a + uniform manner with the rest of the passes being executed.

        + +

        There are many examples of Statistic uses, but the basics of using + it are as follows:

        + +
          +
        1. Define your statistic like this: +
          static Statistic<> NumXForms("mypassname", "The # of times I did stuff");
          + +

          The Statistic template can emulate just about any data-type, + but if you do not specify a template argument, it defaults to acting like + an unsigned int counter (this is usually what you want).

        2. + +
        3. Whenever you make a transformation, bump the counter: +
             ++NumXForms;   // I did stuff
          +
        4. +
        + +

        That's all you have to do. To get 'opt' to print out the + statistics gathered, use the '-stats' option:

        + +
           $ opt -stats -mypassname < program.bc > /dev/null
        ... statistic output ...
        + +

        When running gccas on a C file from the SPEC benchmark + suite, it gives a report that looks like this:

        + +
           7646 bytecodewriter  - Number of normal instructions
        725 bytecodewriter - Number of oversized instructions
        129996 bytecodewriter - Number of bytecode bytes written
        2817 raise - Number of insts DCEd or constprop'd
        3213 raise - Number of cast-of-self removed
        5046 raise - Number of expression trees converted
        75 raise - Number of other getelementptr's formed
        138 raise - Number of load/store peepholes
        42 deadtypeelim - Number of unused typenames removed from symtab
        392 funcresolve - Number of varargs functions resolved
        27 globaldce - Number of global variables removed
        2 adce - Number of basic blocks removed
        134 cee - Number of branches revectored
        49 cee - Number of setcc instruction eliminated
        532 gcse - Number of loads removed
        2919 gcse - Number! of instructions removed
        86 indvars - Number of canonical indvars added
        87 indvars - Number of aux indvars removed
        25 instcombine - Number of dead inst eliminate
        434 instcombine - Number of insts combined
        248 licm - Number of load insts hoisted
        1298 licm - Number of insts hoisted to a loop pre-header
        3 licm - Number of insts hoisted to multiple loop preds (bad, no loop pre-header)
        75 mem2reg - Number of alloca's promoted
        1444 cfgsimplify - Number of blocks simplified
        + +

        Obviously, with so many optimizations, having a unified framework for this + stuff is very nice. Making your pass fit well into the framework makes it more + maintainable and useful.

        + +
        + + + + + +
        + +

        This section describes how to perform some very simple transformations of + LLVM code. This is meant to give examples of common idioms used, showing the + practical side of LLVM transformations.

        Because this is a "how-to" section, + you should also read about the main classes that you will be working with. The + Core LLVM Class Hierarchy Reference contains details + and descriptions of the main classes that you should know about.

        + +
        + + + + + +
        + +

        The LLVM compiler infrastructure have many different data structures that may + be traversed. Following the example of the C++ standard template library, the + techniques used to traverse these various data structures are all basically the + same. For a enumerable sequence of values, the XXXbegin() function (or + method) returns an iterator to the start of the sequence, the XXXend() + function returns an iterator pointing to one past the last valid element of the + sequence, and there is some XXXiterator data type that is common + between the two operations.

        + +

        Because the pattern for iteration is common across many different aspects of + the program representation, the standard template library algorithms may be used + on them, and it is easier to remember how to iterate. First we show a few common + examples of the data structures that need to be traversed. Other data + structures are traversed in very similar ways.

        + +
        + + + + +
        + +

        It's quite common to have a Function instance that you'd like to + transform in some way; in particular, you'd like to manipulate its + BasicBlocks. To facilitate this, you'll need to iterate over all of + the BasicBlocks that constitute the Function. The following is + an example that prints the name of a BasicBlock and the number of + Instructions it contains:

        + +
          // func is a pointer to a Function instance
        for (Function::iterator i = func->begin(), e = func->end(); i != e; ++i) {

        // print out the name of the basic block if it has one, and then the
        // number of instructions that it contains

        cerr << "Basic block (name=" << i->getName() << ") has "
        << i->size() << " instructions.\n";
        }
        + +

        Note that i can be used as if it were a pointer for the purposes of + invoking member functions of the Instruction class. This is + because the indirection operator is overloaded for the iterator + classes. In the above code, the expression i->size() is + exactly equivalent to (*i).size() just like you'd expect.

        + +
        + + + + +
        + +

        Just like when dealing with BasicBlocks in Functions, it's + easy to iterate over the individual instructions that make up + BasicBlocks. Here's a code snippet that prints out each instruction in + a BasicBlock:

        + +
          // blk is a pointer to a BasicBlock instance
        for (BasicBlock::iterator i = blk->begin(), e = blk->end(); i != e; ++i)
        // the next statement works since operator<<(ostream&,...)
        // is overloaded for Instruction&
        cerr << *i << "\n";
        + +

        However, this isn't really the best way to print out the contents of a + BasicBlock! Since the ostream operators are overloaded for virtually + anything you'll care about, you could have just invoked the print routine on the + basic block itself: cerr << *blk << "\n";.

        + +

        Note that currently operator<< is implemented for Value*, so + it will print out the contents of the pointer, instead of the pointer value you + might expect. This is a deprecated interface that will be removed in the + future, so it's best not to depend on it. To print out the pointer value for + now, you must cast to void*.

        + +
        + + + + +
        + +

        If you're finding that you commonly iterate over a Function's + BasicBlocks and then that BasicBlock's Instructions, + InstIterator should be used instead. You'll need to include llvm/Support/InstIterator.h, + and then instantiate InstIterators explicitly in your code. Here's a + small example that shows how to dump all instructions in a function to the standard error stream:

        + +

        #include "llvm/Support/InstIterator.h"
        ...
        // Suppose F is a ptr to a function
        for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i)
        cerr << *i << "\n";
        + Easy, isn't it? You can also use InstIterators to fill a + worklist with its initial contents. For example, if you wanted to + initialize a worklist to contain all instructions in a Function + F, all you would need to do is something like: +
        std::set<Instruction*> worklist;
        worklist.insert(inst_begin(F), inst_end(F));
        + +

        The STL set worklist would now contain all instructions in the + Function pointed to by F.

        + +
        + + + + +
        + +

        Sometimes, it'll be useful to grab a reference (or pointer) to a class + instance when all you've got at hand is an iterator. Well, extracting + a reference or a pointer from an iterator is very straight-forward. + Assuming that i is a BasicBlock::iterator and j + is a BasicBlock::const_iterator:

        + +
            Instruction& inst = *i;   // grab reference to instruction reference
        Instruction* pinst = &*i; // grab pointer to instruction reference
        const Instruction& inst = *j;
        + +

        However, the iterators you'll be working with in the LLVM framework are + special: they will automatically convert to a ptr-to-instance type whenever they + need to. Instead of dereferencing the iterator and then taking the address of + the result, you can simply assign the iterator to the proper pointer type and + you get the dereference and address-of operation as a result of the assignment + (behind the scenes, this is a result of overloading casting mechanisms). Thus + the last line of the last example,

        + +
        Instruction* pinst = &*i;
        + +

        is semantically equivalent to

        + +
        Instruction* pinst = i;
        + +

        It's also possible to turn a class pointer into the corresponding iterator, + and this is a constant time operation (very efficient). The following code + snippet illustrates use of the conversion constructors provided by LLVM + iterators. By using these, you can explicitly grab the iterator of something + without actually obtaining it via iteration over some structure:

        + +
        void printNextInstruction(Instruction* inst) {
        BasicBlock::iterator it(inst);
        ++it; // after this line, it refers to the instruction after *inst.
        if (it != inst->getParent()->end()) cerr << *it << "\n";
        }
        + +
        + + + + +
        + +

        Say that you're writing a FunctionPass and would like to count all the + locations in the entire module (that is, across every Function) where a + certain function (i.e., some Function*) is already in scope. As you'll + learn later, you may want to use an InstVisitor to accomplish this in a + much more straight-forward manner, but this example will allow us to explore how + you'd do it if you didn't have InstVisitor around. In pseudocode, this + is what we want to do:

        + +
        initialize callCounter to zero
        for each Function f in the Module
        for each BasicBlock b in f
        for each Instruction i in b
        if (i is a CallInst and calls the given function)
        increment callCounter
        + +

        And the actual code is (remember, since we're writing a + FunctionPass, our FunctionPass-derived class simply has to + override the runOnFunction method...):

        + +
        Function* targetFunc = ...;

        class OurFunctionPass : public FunctionPass {
        public:
        OurFunctionPass(): callCounter(0) { }

        virtual runOnFunction(Function& F) {
        for (Function::iterator b = F.begin(), be = F.end(); b != be; ++b) {
        for (BasicBlock::iterator i = b->begin(); ie = b->end(); i != ie; ++i) {
        if (CallInst* callInst = dyn_cast<CallInst>(&*i)) {
        // we know we've encountered a call instruction, so we
        // need to determine if it's a call to the
        // function pointed to by m_func or not.

        if (callInst->getCalledFunction() == targetFunc)
        ++callCounter;
        }
        }
        }

        private:
        unsigned callCounter;
        };
        + +
        + + + + +
        + +

        You may have noticed that the previous example was a bit oversimplified in + that it did not deal with call sites generated by 'invoke' instructions. In + this, and in other situations, you may find that you want to treat + CallInsts and InvokeInsts the same way, even though their + most-specific common base class is Instruction, which includes lots of + less closely-related things. For these cases, LLVM provides a handy wrapper + class called CallSite. + It is essentially a wrapper around an Instruction pointer, with some + methods that provide functionality common to CallInsts and + InvokeInsts.

        + +

        This class has "value semantics": it should be passed by value, not by + reference and it should not be dynamically allocated or deallocated using + operator new or operator delete. It is efficiently copyable, + assignable and constructable, with costs equivalents to that of a bare pointer. + If you look at its definition, it has only a single pointer member.

        + +
        + + + + +
        + +

        Frequently, we might have an instance of the Value Class and we want to + determine which Users use the Value. The list of all + Users of a particular Value is called a def-use chain. + For example, let's say we have a Function* named F to a + particular function foo. Finding all of the instructions that + use foo is as simple as iterating over the def-use chain + of F:

        + +
        Function* F = ...;

        for (Value::use_iterator i = F->use_begin(), e = F->use_end(); i != e; ++i) {
        if (Instruction *Inst = dyn_cast<Instruction>(*i)) {
        cerr << "F is used in instruction:\n";
        cerr << *Inst << "\n";
        }
        }
        + +

        Alternately, it's common to have an instance of the User Class and need to know what + Values are used by it. The list of all Values used by a + User is known as a use-def chain. Instances of class + Instruction are common Users, so we might want to iterate over + all of the values that a particular instruction uses (that is, the operands of + the particular Instruction):

        + +
        Instruction* pi = ...;

        for (User::op_iterator i = pi->op_begin(), e = pi->op_end(); i != e; ++i) {
        Value* v = *i;
        ...
        }
        + + + +
        + + + + +
        + +

        There are some primitive transformation operations present in the LLVM + infrastructure that are worth knowing about. When performing + transformations, it's fairly common to manipulate the contents of basic + blocks. This section describes some of the common methods for doing so + and gives example code.

        + +
        + + + + +
        + +

        Instantiating Instructions

        + +

        Creation of Instructions is straight-forward: simply call the + constructor for the kind of instruction to instantiate and provide the necessary + parameters. For example, an AllocaInst only requires a + (const-ptr-to) Type. Thus:

        + +
        AllocaInst* ai = new AllocaInst(Type::IntTy);
        + +

        will create an AllocaInst instance that represents the allocation of + one integer in the current stack frame, at runtime. Each Instruction + subclass is likely to have varying default parameters which change the semantics + of the instruction, so refer to the doxygen documentation for the subclass of + Instruction that you're interested in instantiating.

        + +

        Naming values

        + +

        It is very useful to name the values of instructions when you're able to, as + this facilitates the debugging of your transformations. If you end up looking + at generated LLVM machine code, you definitely want to have logical names + associated with the results of instructions! By supplying a value for the + Name (default) parameter of the Instruction constructor, you + associate a logical name with the result of the instruction's execution at + runtime. For example, say that I'm writing a transformation that dynamically + allocates space for an integer on the stack, and that integer is going to be + used as some kind of index by some other code. To accomplish this, I place an + AllocaInst at the first point in the first BasicBlock of some + Function, and I'm intending to use it within the same + Function. I might do:

        + +
        AllocaInst* pa = new AllocaInst(Type::IntTy, 0, "indexLoc");
        + +

        where indexLoc is now the logical name of the instruction's + execution value, which is a pointer to an integer on the runtime stack.

        + +

        Inserting instructions

        + +

        There are essentially two ways to insert an Instruction + into an existing sequence of instructions that form a BasicBlock:

        + +
          +
        • Insertion into an explicit instruction list + +

          Given a BasicBlock* pb, an Instruction* pi within that + BasicBlock, and a newly-created instruction we wish to insert + before *pi, we do the following:

          + +
            BasicBlock *pb = ...;
          Instruction *pi = ...;
          Instruction *newInst = new Instruction(...);
          pb->getInstList().insert(pi, newInst); // inserts newInst before pi in pb
          + +

          Appending to the end of a BasicBlock is so common that + the Instruction class and Instruction-derived + classes provide constructors which take a pointer to a + BasicBlock to be appended to. For example code that + looked like:

          + +
            BasicBlock *pb = ...;
          Instruction *newInst = new Instruction(...);
          pb->getInstList().push_back(newInst); // appends newInst to pb
          + +

          becomes:

          + +
            BasicBlock *pb = ...;
          Instruction *newInst = new Instruction(..., pb);
          + +

          which is much cleaner, especially if you are creating + long instruction streams.

        • + +
        • Insertion into an implicit instruction list + +

          Instruction instances that are already in BasicBlocks + are implicitly associated with an existing instruction list: the instruction + list of the enclosing basic block. Thus, we could have accomplished the same + thing as the above code without being given a BasicBlock by doing: +

          + +
            Instruction *pi = ...;
          Instruction *newInst = new Instruction(...);
          pi->getParent()->getInstList().insert(pi, newInst);
          + +

          In fact, this sequence of steps occurs so frequently that the + Instruction class and Instruction-derived classes provide + constructors which take (as a default parameter) a pointer to an + Instruction which the newly-created Instruction should + precede. That is, Instruction constructors are capable of + inserting the newly-created instance into the BasicBlock of a + provided instruction, immediately before that instruction. Using an + Instruction constructor with a insertBefore (default) + parameter, the above code becomes:

          + +
          Instruction* pi = ...;
          Instruction* newInst = new Instruction(..., pi);
          + +

          which is much cleaner, especially if you're creating a lot of + instructions and adding them to BasicBlocks.

        • +
        + +
        + + + + +
        + +

        Deleting an instruction from an existing sequence of instructions that form a + BasicBlock is very straight-forward. First, + you must have a pointer to the instruction that you wish to delete. Second, you + need to obtain the pointer to that instruction's basic block. You use the + pointer to the basic block to get its list of instructions and then use the + erase function to remove your instruction. For example:

        + +
          Instruction *I = .. ;
        BasicBlock *BB = I->getParent();
        BB->getInstList().erase(I);
        + +
        + + + + +
        + +

        Replacing individual instructions

        + +

        Including "llvm/Transforms/Utils/BasicBlockUtils.h" + permits use of two very useful replace functions: ReplaceInstWithValue + and ReplaceInstWithInst.

        + +

        Deleting Instructions

        + +
          +
        • ReplaceInstWithValue + +

          This function replaces all uses (within a basic block) of a given + instruction with a value, and then removes the original instruction. The + following example illustrates the replacement of the result of a particular + AllocaInst that allocates memory for a single integer with an null + pointer to an integer.

          + +
          AllocaInst* instToReplace = ...;
          BasicBlock::iterator ii(instToReplace);
          ReplaceInstWithValue(instToReplace->getParent()->getInstList(), ii,
          Constant::getNullValue(PointerType::get(Type::IntTy)));
        • + +
        • ReplaceInstWithInst + +

          This function replaces a particular instruction with another + instruction. The following example illustrates the replacement of one + AllocaInst with another.

          + +
          AllocaInst* instToReplace = ...;
          BasicBlock::iterator ii(instToReplace);
          ReplaceInstWithInst(instToReplace->getParent()->getInstList(), ii,
          new AllocaInst(Type::IntTy, 0, "ptrToReplacedInt"));
        • +
        + +

        Replacing multiple uses of Users and Values

        + +

        You can use Value::replaceAllUsesWith and + User::replaceUsesOfWith to change more than one use at a time. See the + doxygen documentation for the Value Class + and User Class, respectively, for more + information.

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

        The Core LLVM classes are the primary means of representing the program + being inspected or transformed. The core LLVM classes are defined in + header files in the include/llvm/ directory, and implemented in + the lib/VMCore directory.

        + +
        + + + + +
        + +

        #include "llvm/Value.h" +
        + doxygen info: Value Class

        + +

        The Value class is the most important class in the LLVM Source + base. It represents a typed value that may be used (among other things) as an + operand to an instruction. There are many different types of Values, + such as Constants,Arguments. Even Instructions and Functions are Values.

        + +

        A particular Value may be used many times in the LLVM representation + for a program. For example, an incoming argument to a function (represented + with an instance of the Argument class) is "used" by + every instruction in the function that references the argument. To keep track + of this relationship, the Value class keeps a list of all of the Users that is using it (the User class is a base class for all nodes in the LLVM + graph that can refer to Values). This use list is how LLVM represents + def-use information in the program, and is accessible through the use_* + methods, shown below.

        + +

        Because LLVM is a typed representation, every LLVM Value is typed, + and this Type is available through the getType() + method. In addition, all LLVM values can be named. The "name" of the + Value is a symbolic string printed in the LLVM code:

        + +
           %foo = add int 1, 2
        + +

        The name of this instruction is "foo". NOTE + that the name of any value may be missing (an empty string), so names should + ONLY be used for debugging (making the source code easier to read, + debugging printouts), they should not be used to keep track of values or map + between them. For this purpose, use a std::map of pointers to the + Value itself instead.

        + +

        One important aspect of LLVM is that there is no distinction between an SSA + variable and the operation that produces it. Because of this, any reference to + the value produced by an instruction (or the value available as an incoming + argument, for example) is represented as a direct pointer to the instance of + the class that + represents this value. Although this may take some getting used to, it + simplifies the representation and makes it easier to manipulate.

        + +
        + + + + +
        + +
          +
        • Value::use_iterator - Typedef for iterator over the + use-list
          + Value::use_const_iterator - Typedef for const_iterator over + the use-list
          + unsigned use_size() - Returns the number of users of the + value.
          + bool use_empty() - Returns true if there are no users.
          + use_iterator use_begin() - Get an iterator to the start of + the use-list.
          + use_iterator use_end() - Get an iterator to the end of the + use-list.
          + User *use_back() - Returns the last + element in the list. +

          These methods are the interface to access the def-use + information in LLVM. As with all other iterators in LLVM, the naming + conventions follow the conventions defined by the STL.

          +
        • +
        • Type *getType() const +

          This method returns the Type of the Value.

          +
        • +
        • bool hasName() const
          + std::string getName() const
          + void setName(const std::string &Name) +

          This family of methods is used to access and assign a name to a Value, + be aware of the precaution above.

          +
        • +
        • void replaceAllUsesWith(Value *V) + +

          This method traverses the use list of a Value changing all Users of the current value to refer to + "V" instead. For example, if you detect that an instruction always + produces a constant value (for example through constant folding), you can + replace all uses of the instruction with the constant like this:

          + +
            Inst->replaceAllUsesWith(ConstVal);
          +
        + +
        + + + + +
        + +

        + #include "llvm/User.h"
        + doxygen info: User Class
        + Superclass: Value

        + +

        The User class is the common base class of all LLVM nodes that may + refer to Values. It exposes a list of "Operands" + that are all of the Values that the User is + referring to. The User class itself is a subclass of + Value.

        + +

        The operands of a User point directly to the LLVM Value that it refers to. Because LLVM uses Static + Single Assignment (SSA) form, there can only be one definition referred to, + allowing this direct connection. This connection provides the use-def + information in LLVM.

        + +
        + + + + +
        + +

        The User class exposes the operand list in two ways: through + an index access interface and through an iterator based interface.

        + +
          +
        • Value *getOperand(unsigned i)
          + unsigned getNumOperands() +

          These two methods expose the operands of the User in a + convenient form for direct access.

        • + +
        • User::op_iterator - Typedef for iterator over the operand + list
          + User::op_const_iterator use_iterator op_begin() - + Get an iterator to the start of the operand list.
          + use_iterator op_end() - Get an iterator to the end of the + operand list. +

          Together, these methods make up the iterator based interface to + the operands of a User.

        • +
        + +
        + + + + +
        + +

        #include "llvm/Instruction.h"
        + doxygen info: Instruction Class
        + Superclasses: User, Value

        + +

        The Instruction class is the common base class for all LLVM + instructions. It provides only a few methods, but is a very commonly used + class. The primary data tracked by the Instruction class itself is the + opcode (instruction type) and the parent BasicBlock the Instruction is embedded + into. To represent a specific type of instruction, one of many subclasses of + Instruction are used.

        + +

        Because the Instruction class subclasses the User class, its operands can be accessed in the same + way as for other Users (with the + getOperand()/getNumOperands() and + op_begin()/op_end() methods).

        An important file for + the Instruction class is the llvm/Instruction.def file. This + file contains some meta-data about the various different types of instructions + in LLVM. It describes the enum values that are used as opcodes (for example + Instruction::Add and Instruction::SetLE), as well as the + concrete sub-classes of Instruction that implement the instruction (for + example BinaryOperator and SetCondInst). Unfortunately, the use of macros in + this file confuses doxygen, so these enum values don't show up correctly in the + doxygen output.

        + +
        + + + + +
        + +
          +
        • BasicBlock *getParent() +

          Returns the BasicBlock that + this Instruction is embedded into.

        • +
        • bool mayWriteToMemory() +

          Returns true if the instruction writes to memory, i.e. it is a + call,free,invoke, or store.

        • +
        • unsigned getOpcode() +

          Returns the opcode for the Instruction.

        • +
        • Instruction *clone() const +

          Returns another instance of the specified instruction, identical + in all ways to the original except that the instruction has no parent + (ie it's not embedded into a BasicBlock), + and it has no name

        • +
        + +
        + + + + +
        + +

        #include "llvm/BasicBlock.h"
        + doxygen info: BasicBlock + Class
        + Superclass: Value

        + +

        This class represents a single entry multiple exit section of the code, + commonly known as a basic block by the compiler community. The + BasicBlock class maintains a list of Instructions, which form the body of the block. + Matching the language definition, the last element of this list of instructions + is always a terminator instruction (a subclass of the TerminatorInst class).

        + +

        In addition to tracking the list of instructions that make up the block, the + BasicBlock class also keeps track of the Function that it is embedded into.

        + +

        Note that BasicBlocks themselves are Values, because they are referenced by instructions + like branches and can go in the switch tables. BasicBlocks have type + label.

        + +
        + + + + +
        + +
          +
        • BasicBlock(const std::string &Name = "", Function *Parent = 0) +

          The BasicBlock constructor is used to create new basic + blocks for insertion into a function. The constructor optionally takes + a name for the new block, and a Function + to insert it into. If the Parent parameter is specified, the + new BasicBlock is automatically inserted at the end of the + specified Function, if not specified, + the BasicBlock must be manually inserted into the Function.

          +
        • +
        • BasicBlock::iterator - Typedef for instruction list + iterator
          + BasicBlock::const_iterator - Typedef for const_iterator.
          + begin(), end(), front(), back(),size(),empty(),rbegin(),rend() + - STL style functions for accessing the instruction list. +

          These methods and typedefs are forwarding functions that have + the same semantics as the standard library methods of the same names. + These methods expose the underlying instruction list of a basic block in + a way that is easy to manipulate. To get the full complement of + container operations (including operations to update the list), you must + use the getInstList() method.

        • +
        • BasicBlock::InstListType &getInstList() +

          This method is used to get access to the underlying container + that actually holds the Instructions. This method must be used when + there isn't a forwarding function in the BasicBlock class for + the operation that you would like to perform. Because there are no + forwarding functions for "updating" operations, you need to use this if + you want to update the contents of a BasicBlock.

        • +
        • Function *getParent() +

          Returns a pointer to Function + the block is embedded into, or a null pointer if it is homeless.

        • +
        • TerminatorInst *getTerminator() +

          Returns a pointer to the terminator instruction that appears at + the end of the BasicBlock. If there is no terminator + instruction, or if the last instruction in the block is not a + terminator, then a null pointer is returned.

        • +
        + +
        + + + + +
        + +

        #include "llvm/GlobalValue.h"
        + doxygen info: GlobalValue + Class
        + Superclasses: User, Value

        + +

        Global values (GlobalVariables or Functions) are the only LLVM values that are + visible in the bodies of all Functions. + Because they are visible at global scope, they are also subject to linking with + other globals defined in different translation units. To control the linking + process, GlobalValues know their linkage rules. Specifically, + GlobalValues know whether they have internal or external linkage, as + defined by the LinkageTypes enumeration.

        + +

        If a GlobalValue has internal linkage (equivalent to being + static in C), it is not visible to code outside the current translation + unit, and does not participate in linking. If it has external linkage, it is + visible to external code, and does participate in linking. In addition to + linkage information, GlobalValues keep track of which Module they are currently part of.

        + +

        Because GlobalValues are memory objects, they are always referred to + by their address. As such, the Type of a + global is always a pointer to its contents. It is important to remember this + when using the GetElementPtrInst instruction because this pointer must + be dereferenced first. For example, if you have a GlobalVariable (a + subclass of GlobalValue) that is an array of 24 ints, type [24 x + int], then the GlobalVariable is a pointer to that array. Although + the address of the first element of this array and the value of the + GlobalVariable are the same, they have different types. The + GlobalVariable's type is [24 x int]. The first element's type + is int. Because of this, accessing a global value requires you to + dereference the pointer with GetElementPtrInst first, then its elements + can be accessed. This is explained in the LLVM + Language Reference Manual.

        + +
        + + + + +
        + +
          +
        • bool hasInternalLinkage() const
          + bool hasExternalLinkage() const
          + void setInternalLinkage(bool HasInternalLinkage) +

          These methods manipulate the linkage characteristics of the GlobalValue.

          +

          +
        • +
        • Module *getParent() +

          This returns the Module that the + GlobalValue is currently embedded into.

        • +
        + +
        + + + + +
        + +

        #include "llvm/Function.h"
        doxygen + info: Function Class
        + Superclasses: GlobalValue, User, Value

        + +

        The Function class represents a single procedure in LLVM. It is + actually one of the more complex classes in the LLVM heirarchy because it must + keep track of a large amount of data. The Function class keeps track + of a list of BasicBlocks, a list of formal Arguments, and a SymbolTable.

        + +

        The list of BasicBlocks is the most + commonly used part of Function objects. The list imposes an implicit + ordering of the blocks in the function, which indicate how the code will be + layed out by the backend. Additionally, the first BasicBlock is the implicit entry node for the + Function. It is not legal in LLVM to explicitly branch to this initial + block. There are no implicit exit nodes, and in fact there may be multiple exit + nodes from a single Function. If the BasicBlock list is empty, this indicates that + the Function is actually a function declaration: the actual body of the + function hasn't been linked in yet.

        + +

        In addition to a list of BasicBlocks, the + Function class also keeps track of the list of formal Arguments that the function receives. This + container manages the lifetime of the Argument + nodes, just like the BasicBlock list does for + the BasicBlocks.

        + +

        The SymbolTable is a very rarely used + LLVM feature that is only used when you have to look up a value by name. Aside + from that, the SymbolTable is used + internally to make sure that there are not conflicts between the names of Instructions, BasicBlocks, or Arguments in the function body.

        + +

        Note that Function is a GlobalValue + and therefore also a Constant. The value of the function + is its address (after linking) which is guaranteed to be constant.

        +
        + + + + +
        + +
          +
        • Function(const FunctionType + *Ty, LinkageTypes Linkage, const std::string &N = "", Module* Parent = 0) + +

          Constructor used when you need to create new Functions to add + the the program. The constructor must specify the type of the function to + create and what type of linkage the function should have. The FunctionType argument + specifies the formal arguments and return value for the function. The same + FunctionType value can be used to + create multiple functions. The Parent argument specifies the Module + in which the function is defined. If this argument is provided, the function + will automatically be inserted into that module's list of + functions.

        • + +
        • bool isExternal() + +

          Return whether or not the Function has a body defined. If the + function is "external", it does not have a body, and thus must be resolved + by linking with a function defined in a different translation unit.

        • + +
        • Function::iterator - Typedef for basic block list iterator
          + Function::const_iterator - Typedef for const_iterator.
          + + begin(), end(), front(), back(), + size(), empty(), rbegin(), rend() + +

          These are forwarding methods that make it easy to access the contents of + a Function object's BasicBlock + list.

        • + +
        • Function::BasicBlockListType &getBasicBlockList() + +

          Returns the list of BasicBlocks. This + is necessary to use when you need to update the list or perform a complex + action that doesn't have a forwarding method.

        • + +
        • Function::aiterator - Typedef for the argument list + iterator
          + Function::const_aiterator - Typedef for const_iterator.
          + + abegin(), aend(), afront(), aback(), + asize(), aempty(), arbegin(), arend() + +

          These are forwarding methods that make it easy to access the contents of + a Function object's Argument + list.

        • + +
        • Function::ArgumentListType &getArgumentList() + +

          Returns the list of Arguments. This is + necessary to use when you need to update the list or perform a complex + action that doesn't have a forwarding method.

        • + +
        • BasicBlock &getEntryBlock() + +

          Returns the entry BasicBlock for the + function. Because the entry block for the function is always the first + block, this returns the first block of the Function.

        • + +
        • Type *getReturnType()
          + FunctionType *getFunctionType() + +

          This traverses the Type of the + Function and returns the return type of the function, or the FunctionType of the actual + function.

        • + +
        • SymbolTable *getSymbolTable() + +

          Return a pointer to the SymbolTable + for this Function.

        • +
        + +
        + + + + +
        + +

        #include "llvm/GlobalVariable.h" +
        + doxygen info: GlobalVariable + Class
        Superclasses: GlobalValue, User, Value

        + +

        Global variables are represented with the (suprise suprise) + GlobalVariable class. Like functions, GlobalVariables are also + subclasses of GlobalValue, and as such are + always referenced by their address (global values must live in memory, so their + "name" refers to their address). See GlobalValue for more on this. Global variables + may have an initial value (which must be a Constant), and if they have an initializer, they + may be marked as "constant" themselves (indicating that their contents never + change at runtime).

        + +
        + + + + +
        + +
          +
        • GlobalVariable(const Type *Ty, bool + isConstant, LinkageTypes& Linkage, Constant + *Initializer = 0, const std::string &Name = "", Module* Parent = 0) + +

          Create a new global variable of the specified type. If + isConstant is true then the global variable will be marked as + unchanging for the program. The Linkage parameter specifies the type of + linkage (internal, external, weak, linkonce, appending) for the variable. If + the linkage is InternalLinkage, WeakLinkage, or LinkOnceLinkage,  then + the resultant global variable will have internal linkage. AppendingLinkage + concatenates together all instances (in different translation units) of the + variable into a single variable but is only applicable to arrays.  See + the LLVM Language Reference for + further details on linkage types. Optionally an initializer, a name, and the + module to put the variable into may be specified for the global variable as + well.

        • + +
        • bool isConstant() const + +

          Returns true if this is a global variable that is known not to + be modified at runtime.

        • + +
        • bool hasInitializer() + +

          Returns true if this GlobalVariable has an intializer.

        • + +
        • Constant *getInitializer() + +

          Returns the intial value for a GlobalVariable. It is not legal + to call this method if there is no initializer.

        • +
        + +
        + + + + +
        + +

        #include "llvm/Module.h"
        doxygen info: + Module Class

        + +

        The Module class represents the top level structure present in LLVM + programs. An LLVM module is effectively either a translation unit of the + original program or a combination of several translation units merged by the + linker. The Module class keeps track of a list of Functions, a list of GlobalVariables, and a SymbolTable. Additionally, it contains a few + helpful member functions that try to make common operations easy.

        + +
        + + + + +
        + +
          +
        • Module::Module(std::string name = "")
        • +
        + +

        Constructing a Module is easy. You can optionally + provide a name for it (probably based on the name of the translation unit).

        + +
          +
        • Module::iterator - Typedef for function list iterator
          + Module::const_iterator - Typedef for const_iterator.
          + + begin(), end(), front(), back(), + size(), empty(), rbegin(), rend() + +

          These are forwarding methods that make it easy to access the contents of + a Module object's Function + list.

        • + +
        • Module::FunctionListType &getFunctionList() + +

          Returns the list of Functions. This is + necessary to use when you need to update the list or perform a complex + action that doesn't have a forwarding method.

          + +

        • +
        + +
        + +
          +
        • Module::giterator - Typedef for global variable list iterator
          + + Module::const_giterator - Typedef for const_iterator.
          + + gbegin(), gend(), gfront(), gback(), + gsize(), gempty(), grbegin(), grend() + +

          These are forwarding methods that make it easy to access the contents of + a Module object's GlobalVariable list.

        • + +
        • Module::GlobalListType &getGlobalList() + +

          Returns the list of GlobalVariables. This is necessary to + use when you need to update the list or perform a complex action that + doesn't have a forwarding method.

          + +

        • +
        + +
        + + + +
        + +
          +
        • Function *getFunction(const std::string + &Name, const FunctionType *Ty) + +

          Look up the specified function in the Module SymbolTable. If it does not exist, return + null.

        • + +
        • Function *getOrInsertFunction(const + std::string &Name, const FunctionType *T) + +

          Look up the specified function in the Module SymbolTable. If it does not exist, add an + external declaration for the function and return it.

        • + +
        • std::string getTypeName(const Type *Ty) + +

          If there is at least one entry in the SymbolTable for the specified Type, return it. Otherwise return the empty + string.

        • + +
        • bool addTypeName(const std::string &Name, const Type *Ty) + +

          Insert an entry in the SymbolTable + mapping Name to Ty. If there is already an entry for this + name, true is returned and the SymbolTable is not modified.

        • +
        + +
        + + + + +
        + +

        Constant represents a base class for different types of constants. It + is subclassed by ConstantBool, ConstantInt, ConstantSInt, ConstantUInt, + ConstantArray etc for representing the various types of Constants.

        + +
        + + + + +
        + +
          +
          Important Subclasses of Constant +

          +
            +
          • ConstantSInt : This subclass of Constant represents a signed + integer constant. +
              +
            • int64_t getValue() const: Returns the underlying value of + this constant.
            • +
            +
          • +
          • ConstantUInt : This class represents an unsigned integer. +
              +
            • uint64_t getValue() const: Returns the underlying value + of this constant.
            • +
            +
          • +
          • ConstantFP : This class represents a floating point constant. +
              +
            • double getValue() const: Returns the underlying value of + this constant.
            • +
            +
          • +
          • ConstantBool : This represents a boolean constant. +
              +
            • bool getValue() const: Returns the underlying value of + this constant.
            • +
            +
          • +
          • ConstantArray : This represents a constant array. +
              +
            • const std::vector<Use> &getValues() const: + Returns a Vecotr of component constants that makeup this array.
            • +
            +
          • +
          • ConstantStruct : This represents a constant struct. +
              +
            • const std::vector<Use> &getValues() const: + Returns a Vecotr of component constants that makeup this array.
            • +
            +
          • +
          • GlobalValue : This represents either a global variable or a + function. In either case, the value is a constant fixed address + (after linking). +
          • +
          + +
        +
        + + + + +
        + +

        Type as noted earlier is also a subclass of a Value class. Any primitive + type (like int, short etc) in LLVM is an instance of Type Class. All other + types are instances of subclasses of type like FunctionType, ArrayType + etc. DerivedType is the interface for all such dervied types including + FunctionType, ArrayType, PointerType, StructType. Types can have names. They can + be recursive (StructType). There exists exactly one instance of any type + structure at a time. This allows using pointer equality of Type *s for comparing + types.

        + +
        + + + + +
        + +
          + +
        • bool isSigned() const: Returns 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.
        • + +
        • bool isUnsigned() const: Returns whether a numeric type is + unsigned. This is not quite the complement of isSigned... nonnumeric types + return false as they do with isSigned. This returns true for UByteTy, + UShortTy, UIntTy, and ULongTy.
        • + +
        • bool isInteger() const: Equivalent to isSigned() || isUnsigned().
        • + +
        • bool isIntegral() const: Returns true if this is an integral + type, which is either Bool type or one of the Integer types.
        • + +
        • bool isFloatingPoint(): Return true if this is one of the two + floating point types.
        • + +
        • isLosslesslyConvertableTo (const Type *Ty) const: Return true if + this type can be converted to 'Ty' without any reinterpretation of bits. For + example, uint to int or one pointer type to another.
        • + +
          +

          Derived Types

          + +
            +
          • SequentialType : This is subclassed by ArrayType and PointerType +
              +
            • const Type * getElementType() const: Returns the type of + each of the elements in the sequential type.
            • +
            +
          • +
          • ArrayType : This is a subclass of SequentialType and defines + interface for array types. +
              +
            • unsigned getNumElements() const: Returns the number of + elements in the array.
            • +
            +
          • +
          • PointerType : Subclass of SequentialType for pointer types.
          • +
          • StructType : subclass of DerivedTypes for struct types
          • +
          • FunctionType : subclass of DerivedTypes for function types. +
              +
            • bool isVarArg() const: Returns true if its a vararg + function
            • +
            • const Type * getReturnType() const: Returns the + return type of the function.
            • +
            • const Type * getParamType (unsigned i): Returns + the type of the ith parameter.
            • +
            • const unsigned getNumParams() const: Returns the + number of formal parameters.
            • +
            +
          • +
          + +
        + +
        + + + + +
        + +

        This subclass of Value defines the interface for incoming formal + arguments to a function. A Function maitanis a list of its formal + arguments. An argument has a pointer to the parent Function.

        + +
        + + + +
        +

        This class provides a symbol table that the + Function and + Module classes use for naming definitions. The symbol table can + provide a name for any Value or + Type. SymbolTable is an abstract data + type. It hides the data it contains and provides access to it through a + controlled interface.

        + +

        To use the SymbolTable well, you need to understand the + structure of the information it holds. The class contains two + std::map objects. The first, pmap, is a map of + Type* to maps of name (std::string) to Value*. + The second, tmap, is a map of names to Type*. Thus, Values + are stored in two-dimensions and accessed by Type and name. Types, + however, are stored in a single dimension and accessed only by name.

        + +

        The interface of this class provides three basic types of operations: +

          +
        1. Accessors. Accessors provide read-only access to information + such as finding a value for a name with the + lookup method.
        2. +
        3. Mutators. Mutators allow the user to add information to the + SymbolTable with methods like + insert.
        4. +
        5. Iterators. Iterators allow the user to traverse the content + of the symbol table in well defined ways, such as the method + type_begin.
        6. +
        + +

        Accessors

        +
        +
        Value* lookup(const Type* Ty, const std::string& name) const: +
        +
        The lookup method searches the type plane given by the + Ty parameter for a Value with the provided name. + If a suitable Value is not found, null is returned.
        + +
        Type* lookupType( const std::string& name) const:
        +
        The lookupType method searches through the types for a + Type with the provided name. If a suitable Type + is not found, null is returned.
        + +
        bool hasTypes() const:
        +
        This function returns true if an entry has been made into the type + map.
        + +
        bool isEmpty() const:
        +
        This function returns true if both the value and types maps are + empty
        + +
        std::string get_name(const Value*) const:
        +
        This function returns the name of the Value provided or the empty + string if the Value is not in the symbol table.
        + +
        std::string get_name(const Type*) const:
        +
        This function returns the name of the Type provided or the empty + string if the Type is not in the symbol table.
        +
        + +

        Mutators

        +
        +
        void insert(Value *Val):
        +
        This method adds the provided value to the symbol table. The Value must + have both a name and a type which are extracted and used to place the value + in the correct type plane under the value's name.
        + +
        void insert(const std::string& Name, Value *Val):
        +
        Inserts a constant or type into the symbol table with the specified + name. There can be a many to one mapping between names and constants + or types.
        + +
        void insert(const std::string& Name, Type *Typ):
        +
        Inserts a type into the symbol table with the specified name. There + can be a many-to-one mapping between names and types. This method + allows a type with an existing entry in the symbol table to get + a new name.
        + +
        void remove(Value* Val):
        +
        This method removes a named value from the symbol table. The + type and name of the Value are extracted from \p N and used to + lookup the Value in the correct type plane. If the Value is + not in the symbol table, this method silently ignores the + request.
        + +
        void remove(Type* Typ):
        +
        This method removes a named type from the symbol table. The + name of the type is extracted from \P T and used to look up + the Type in the type map. If the Type is not in the symbol + table, this method silently ignores the request.
        + +
        Value* remove(const std::string& Name, Value *Val):
        +
        Remove a constant or type with the specified name from the + symbol table.
        + +
        Type* remove(const std::string& Name, Type* T):
        +
        Remove a type with the specified name from the symbol table. + Returns the removed Type.
        + +
        Value *value_remove(const value_iterator& It):
        +
        Removes a specific value from the symbol table. + Returns the removed value.
        + +
        bool strip():
        +
        This method will strip the symbol table of its names leaving + the type and values.
        + +
        void clear():
        +
        Empty the symbol table completely.
        +
        + +

        Iteration

        +

        The following functions describe three types of iterators you can obtain + the beginning or end of the sequence for both const and non-const. It is + important to keep track of the different kinds of iterators. There are + three idioms worth pointing out:

        + + + + + + + + + + + + + + +
        UnitsIteratorIdiom
        Planes Of name/Value mapsPI
        + for (SymbolTable::plane_const_iterator PI = ST.plane_begin(),
        + PE = ST.plane_end(); PI != PE; ++PI ) {
        +   PI->first // This is the Type* of the plane
        +   PI->second // This is the SymbolTable::ValueMap of name/Value pairs
        +     
        All name/Type PairsTI
        + for (SymbolTable::type_const_iterator TI = ST.type_begin(),
        +      TE = ST.type_end(); TI != TE; ++TI )
        +   TI->first  // This is the name of the type
        +   TI->second // This is the Type* value associated with the name
        +     
        name/Value pairs in a planeVI
        + for (SymbolTable::value_const_iterator VI = ST.value_begin(SomeType),
        +      VE = ST.value_end(SomeType); VI != VE; ++VI )
        +   VI->first  // This is the name of the Value
        +   VI->second // This is the Value* value associated with the name
        +     
        +

        Using the recommended iterator names and idioms will help you avoid + making mistakes. Of particular note, make sure that whenever you use + value_begin(SomeType) that you always compare the resulting iterator + with value_end(SomeType) not value_end(SomeOtherType) or else you + will loop infinitely.

        + +
        + +
        plane_iterator plane_begin():
        +
        Get an iterator that starts at the beginning of the type planes. + The iterator will iterate over the Type/ValueMap pairs in the + type planes.
        + +
        plane_const_iterator plane_begin() const:
        +
        Get a const_iterator that starts at the beginning of the type + planes. The iterator will iterate over the Type/ValueMap pairs + in the type planes.
        + +
        plane_iterator plane_end():
        +
        Get an iterator at the end of the type planes. This serves as + the marker for end of iteration over the type planes.
        + +
        plane_const_iterator plane_end() const:
        +
        Get a const_iterator at the end of the type planes. This serves as + the marker for end of iteration over the type planes.
        + +
        value_iterator value_begin(const Type *Typ):
        +
        Get an iterator that starts at the beginning of a type plane. + The iterator will iterate over the name/value pairs in the type plane. + Note: The type plane must already exist before using this.
        + +
        value_const_iterator value_begin(const Type *Typ) const:
        +
        Get a const_iterator that starts at the beginning of a type plane. + The iterator will iterate over the name/value pairs in the type plane. + Note: The type plane must already exist before using this.
        + +
        value_iterator value_end(const Type *Typ):
        +
        Get an iterator to the end of a type plane. This serves as the marker + for end of iteration of the type plane. + Note: The type plane must already exist before using this.
        + +
        value_const_iterator value_end(const Type *Typ) const:
        +
        Get a const_iterator to the end of a type plane. This serves as the + marker for end of iteration of the type plane. + Note: the type plane must already exist before using this.
        + +
        type_iterator type_begin():
        +
        Get an iterator to the start of the name/Type map.
        + +
        type_const_iterator type_begin() cons:
        +
        Get a const_iterator to the start of the name/Type map.
        + +
        type_iterator type_end():
        +
        Get an iterator to the end of the name/Type map. This serves as the + marker for end of iteration of the types.
        + +
        type_const_iterator type_end() const:
        +
        Get a const-iterator to the end of the name/Type map. This serves + as the marker for end of iteration of the types.
        + +
        plane_const_iterator find(const Type* Typ ) const:
        +
        This method returns a plane_const_iterator for iteration over + the type planes starting at a specific plane, given by \p Ty.
        + +
        plane_iterator find( const Type* Typ :
        +
        This method returns a plane_iterator for iteration over the + type planes starting at a specific plane, given by \p Ty.
        + +
        const ValueMap* findPlane( const Type* Typ ) cons:
        +
        This method returns a ValueMap* for a specific type plane. This + interface is deprecated and may go away in the future.
        +
        +
        + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Dinakar Dhurjati and + Chris Lattner
        + The LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:04 $ +
        + + + + Index: llvm-www/releases/1.3/docs/Projects.html diff -c /dev/null llvm-www/releases/1.3/docs/Projects.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/Projects.html Fri Aug 13 17:03:04 2004 *************** *** 0 **** --- 1,451 ---- + + + + Creating an LLVM Project + + + + +
        Creating an LLVM Project
        + +
          +
        1. Overview
        2. +
        3. Create a project from the Sample Project
        4. +
        5. Source tree layout
        6. +
        7. Writing LLVM-style Makefiles +
            +
          1. Required Variables
          2. +
          3. Variables for Building Subdirectories
          4. +
          5. Variables for Building Libraries
          6. +
          7. Variables for Building Programs
          8. +
          9. Miscellaneous Variables
          10. +
        8. +
        9. Placement of object code
        10. +
        11. Further help
        12. +
        + +
        +

        Written by John Criswell

        +
        + + + + + +
        + +

        The LLVM build system is designed to facilitate the building of third party + projects that use LLVM header files, libraries, and tools. In order to use + these facilities, a Makefile from a project must do the following things:

        + +
          +
        1. Set environment variables.There are several environment variables that a + Makefile needs to set to use the LLVM build system: + +
            +
          • LLVM_SRC_ROOT - The root of the LLVM source tree.
          • +
          • LLVM_OBJ_ROOT - The root of the LLVM object tree.
          • +
          • BUILD_SRC_ROOT - The root of the project's source tree.
          • +
          • BUILD_OBJ_ROOT - The root of the project's object tree.
          • +
          • BUILD_SRC_DIR - The directory containing the current source to be + compiled.
          • +
          • BUILD_OBJ_DIR - The directory where the current source will place + the new object files. This should always be the current directory.
          • +
          • LEVEL - The relative path from the current directory to the root + of the object tree.
          • +
        2. +
        3. Include Makefile.config from $(LLVM_OBJ_ROOT).
        4. +
        5. Include Makefile.rules from $(LLVM_SRC_ROOT).
        6. +
        + +

        There are two ways that you can set all of these variables:

        + +
          +
        1. You can write your own Makefiles which hard-code these values.
        2. + +
        3. You can use the pre-made LLVM sample project. This sample project includes + Makefiles, a configure script that can be used to configure the location of + LLVM, and the ability to support multiple object directories from a single + source directory.
        4. +
        + +

        This document assumes that you will base your project off of the LLVM sample + project found in llvm/projects/sample. If you want to devise your own + build system, studying the sample project and LLVM Makefiles will probably + provide enough information on how to write your own Makefiles.

        + +
        + + + + + +
        + +

        Follow these simple steps to start your project:

        + +
          +
        1. Copy the llvm/projects/sample directory to any place of your + choosing. You can place it anywhere you like. Rename the directory to match + the name of your project.
        2. + +
        3. Add your source code and Makefiles to your source tree.
        4. + +
        5. If you want your Makefiles to be configured by the configure + script, or if you want to support multiple object directories, add your + Makefiles to the configure script by adding them into the + autoconf/configure.ac file. The macro AC_CONFIG_MAKEFILE will + copy a file, unmodified, from the source directory to the object directory.
        6. + +
        7. After updating autoconf/configure.ac, regenerate the + configure script with these commands: + +
          +

          % cd autoconf
          + % autoconf -o ../configure

          +
          + +

          You must be using Autoconf version 2.57 or higher.

        8. + +
        9. Run configure in the directory in which you want to place + object code. Use the following options to tell your project where it + can find LLVM: + +
          +
          --with-llvmsrc=<directory> +
          + Tell your project where the LLVM source tree is located. +

          +

          --with-llvmobj=<directory> +
          + Tell your project where the LLVM object tree is located. +
          +
        + +

        That's it! Now all you have to do is type gmake in the root of + your object directory, and your project should build.

        + +
        + + + + + +
        + +

        In order to use the LLVM build system, you will want to organize your + source code so that it can benefit from the build system's features. + Mainly, you want your source tree layout to look similar to the LLVM + source tree layout. The best way to do this is to just copy the + project tree from llvm/projects/sample and modify it to meet + your needs, but you can certainly add to it if you want.

        + +

        Underneath your top level directory, you should have the following + directories:

        + +
        +
        lib +
        + This subdirectory should contain all of your library source + code. For each library that you build, you will have one + directory in lib that will contain that library's source + code. + +

        + Libraries can be object files, archives, or dynamic libraries. + The lib directory is just a convenient place for libraries + as it places them all in a directory from which they can be linked + later. + +

        include +
        + This subdirectory should contain any header files that are + global to your project. By global, we mean that they are used + by more than one library or executable of your project. +

        + By placing your header files in include, they will be + found automatically by the LLVM build system. For example, if + you have a file include/jazz/note.h, then your source + files can include it simply with #include "jazz/note.h". + +

        tools +
        + This subdirectory should contain all of your source + code for executables. For each program that you build, you + will have one directory in tools that will contain that + program's source code. +

        + +

        test +
        + This subdirectory should contain tests that verify that your code + works correctly. Automated tests are especially useful. +

        + Currently, the LLVM build system provides little support for tests, + although some exists. Expanded support for tests will hopefully + occur in the future. In the meantime, the LLVM system does provide the + following: +

          +
        • + LLVM provides several QMTest test classes that can be used to + create tests. They can be found in + llvm/test/QMTest/llvm.py. These test classes perform a + variety of functions, including code optimization tests, assembly + tests, and code analysis tests. The Makefile in + llvm/test provides the QMTest context needed by LLVM test + classes. +

          + +

        • + The LLVM source tree provides benchmarks and programs which are + known to compile with the LLVM GCC front ends. You can use these + programs to test your code, gather statistics information, and + compare it to the current LLVM performance statistics. These + programs are found in the llvm/test/Programs directory. +

          + Currently, there is no way to hook your tests directly into the + llvm/test/Programs testing harness. You will simply + need to find a way to use the source provided within that directory + on your own. +

        +
        + +

        Typically, you will want to build your lib directory first followed by + your tools directory.

        + +
        + + + + + +
        + +

        The LLVM build system provides a convenient way to build libraries and + executables. Most of your project Makefiles will only need to define a few + variables. Below is a list of the variables one can set and what they can + do:

        + +
        + + + + +
        + +
        +
        LEVEL +
        + This variable is the relative path from this Makefile to the + top directory of your project's source code. For example, if + your source code is in /tmp/src, then the Makefile in + /tmp/src/jump/high would set LEVEL to "../..". +
        + +
        + + + + +
        + +
        +
        DIRS +
        + This is a space separated list of subdirectories that should be + built. They will be built, one at a time, in the order + specified. +

        + +

        PARALLEL_DIRS +
        + This is a list of directories that can be built in parallel. + These will be built after the directories in DIRS have been + built. +

        + +

        OPTIONAL_DIRS +
        + This is a list of directories that can be built if they exist, + but will not cause an error if they do not exist. They are + built serially in the order in which they are listed. +
        + +
        + + + + +
        + +
        +
        LIBRARYNAME +
        + This variable contains the base name of the library that will + be built. For example, to build a library named + libsample.a, LIBRARYNAME should be set to + sample. +

        + +

        BUILD_ARCHIVE +
        + By default, a library is a .o file that is linked + directly into a program. To build an archive (also known as + a static library), set the BUILD_ARCHIVE variable. +

        + +

        SHARED_LIBRARY +
        + If SHARED_LIBRARY is defined in your Makefile, a shared + (or dynamic) library will be built. +
        + +
        + + + + +
        + +
        +
        TOOLNAME +
        + This variable contains the name of the program that will + be built. For example, to build an executable named + sample, TOOLNAME should be set to sample. +

        + +

        USEDLIBS +
        + This variable holds a space separated list of libraries that + should be linked into the program. These libraries must either + be LLVM libraries or libraries that come from your lib + directory. The libraries must be specified by their base name. + For example, to link libsample.a, you would set USEDLIBS to + sample. +

        + Note that this works only for statically linked libraries. +

        + +

        LIBS +
        + To link dynamic libraries, add -l<library base name> to + the LIBS variable. The LLVM build system will look in the same places + for dynamic libraries as it does for static libraries. +

        + For example, to link libsample.so, you would have the + following line in your Makefile: +

        + + LIBS += -lsample + +

        + +
        + + + + +
        + +
        +
        ExtraSource +
        + This variable contains a space separated list of extra source + files that need to be built. It is useful for including the + output of Lex and Yacc programs. +

        + +

        CFLAGS +
        CPPFLAGS +
        + This variable can be used to add options to the C and C++ + compiler, respectively. It is typically used to add options + that tell the compiler the location of additional directories + to search for header files. +

        + It is highly suggested that you append to CFLAGS and CPPFLAGS as + opposed to overwriting them. The master Makefiles may already + have useful options in them that you may not want to overwrite. +

        +

        + +
        + + + + + +
        + +

        The final location of built libraries and executables will depend upon + whether you do a Debug, Release, or Profile build.

        + +
        +
        Libraries +
        + All libraries (static and dynamic) will be stored in + BUILD_OBJ_ROOT/lib/<type>, where type is Debug, + Release, or Profile for a debug, optimized, or + profiled build, respectively.

        + +

        Executables +
        All executables will be stored in + BUILD_OBJ_ROOT/tools/<type>, where type is Debug, + Release, or Profile for a debug, optimized, or profiled + build, respectively. +
        + +
        + + + + + +
        + +

        If you have any questions or need any help creating an LLVM project, + the LLVM team would be more than happy to help. You can always post your + questions to the LLVM Developers + Mailing List.

        + +
        + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + John Criswell
        + The LLVM Compiler Infrastructure +
        + Last modified: $Date: 2004/08/13 22:03:04 $ +
        + + + Index: llvm-www/releases/1.3/docs/ReleaseNotes.html diff -c /dev/null llvm-www/releases/1.3/docs/ReleaseNotes.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/ReleaseNotes.html Fri Aug 13 17:03:04 2004 *************** *** 0 **** --- 1,773 ---- + + + + + LLVM 1.3 Release Notes + + + +
        LLVM 1.3 Release Notes
        + +
          +
        1. Introduction
        2. +
        3. What's New?
        4. +
        5. Installation Instructions
        6. +
        7. Portability and Supported Platforms
        8. +
        9. Known Problems +
        10. +
        11. Additional Information
        12. +
        + +
        +

        Written by the LLVM team

        +

        + + + + + +
        + +

        This document contains the release notes for the LLVM compiler + infrastructure, release 1.3. Here we describe the status of LLVM, including any + known problems and bug fixes from the previous release. The most up-to-date + version of this document can be found on the LLVM 1.3 web site. If you are + not reading this on the LLVM web pages, you should probably go there because + this document may be updated after the release.

        + +

        For more information about LLVM, including information about potentially more + current releases, please check out the main + web site. If you have questions or comments, the LLVM developer's mailing + list is a good place to send them.

        + +

        Note that if you are reading this file from CVS, this document applies + to the next release, not the current one. To see the release notes for + the current or previous releases, see the releases page.

        + +
        + + + + + +
        + +

        This is the fourth public release of the LLVM compiler infrastructure. This + release primarily improves the performance of the + code produced by all aspects of the LLVM compiler, adds many new features, fixes a few + bugs, speeds up the compiler, and introduces a new (experimental) + PowerPC code generator.

        + +

        At this time, LLVM is known to correctly compile and run all C & C++ + SPEC CPU95 & 2000 benchmarks, the Olden benchmarks, and the Ptrdist + benchmarks, and many other programs. LLVM now also works + with a broad variety of C++ programs.

        + +
        + + + + +
        + +
          +
        1. The LLVM select instruction is + now fully implemented and supported by all transformations, native code + generators, and the interpreter.
        2. +
        3. Bugpoint can now narrow down code-generation bugs to a loop nest, where + before it could only narrow them down to a function being miscompiled.
        4. +
        5. Bugpoint can now debug arbitrary + modes of llc and lli, by passing them command line flags (e.g. + -regalloc=linearscan).
        6. +
        7. The Control Flow Graph in the native code generators is no longer + constrained to be the same as the CFG for the LLVM input code.
        8. +
        9. The LLVM induction variable analysis routines have been rewritten.
        10. +
        11. LLVM now has new loop unrolling and loop unswitching passes.
        12. +
        13. The induction variable substitution pass performs linear function test + replacement and exit value replacement optimizations.
        14. +
        15. LLVM now has first-class support for Accurate Garbage Collection, enabling the use + of aggressive copying and generational collectors.
        16. +
        17. LLVM now includes a simple implementation of Andersen's interprocedural alias + analysis algorithm.
        18. +
        19. Bugpoint can extract individual + basic blocks to track down reduce miscompilation testcases.
        20. +
        21. LLVM and the C front-end now work under Win32 using the + Cygwin runtime libraries. + This includes the JIT compiler.
        22. +
        23. The LLVM code generator is now being documented.
        24. +
        25. LLVM includes a new tool, llvm-bcanalyzer, This tool + can compute various statistics and dump information about LLVM bytecode + encoding.
        26. +
        27. The LLVM bytecode file format is now + documented.
        28. +
        29. LLVM now provides an llvm.isunordered intrinsic for efficient + implementation of unordered floating point comparisons.
        30. +
        31. The llvmgcc front-end now supports the GCC builtins for ISO C99 floating + point comparison macros (e.g., __builtin_islessequal).
        32. +
        33. We now generate HTML documentation and man pages + for the tools from a single source (perl-style POD files).
        34. +
        35. The LLVM code generator can now dynamically load targets from shared + objects.
        36. +
        37. LLVM now includes a "skeleton" target, which makes it easier to get + started porting LLVM to new architectures.
        38. +
        39. The linear scan register allocator is now enabled by default in the + target-independent code generator.
        40. +
        41. LLVM now includes a dead store elimination pass.
        42. +
        43. Bugpoint can now debug miscompilations that lead to the program going + into an infinite loop.
        44. +
        45. LLVM now provides interfaces to support ML-style pattern matching on the + LLVM IR.
        46. +
        47. LLVM now includes a context-sensitive mod/ref analysis + for global variables, which is now enabled by default in gccld.
        48. +
        49. LLVM can now autogenerate assembly printers for code generators from the + tablegen description of the target (before they were hand coded).
        50. +
        51. All LLVM tools will now respond to the + --version option which + will tell you the version of LLVM on which the tool is based.
        52. +
        53. An experimental PowerPC backend has been added, capable of compiling several + SPEC benchmarks.
        54. +
        + +
        + + + +
        + In this release, the following missing features were implemented: +
        + + + + + + +
        + +
          +
        1. LLVM tools will happily spew + bytecode onto your terminal
        2. +
        3. [llvmgcc] type names are not emitted + for structure typedefs
        4. +
        5. All documentation is now conformant to the HTML 4.01 (Strict) level.
        6. +
        7. The spurious "WARNING: Found global types that are not compatible" warning + produced when linking C++ programs has been fixed.
        8. +
        9. lli Doesn't Handle Exceptions From + Bytecode Reader
        10. +
        11. Global Vars Have (Somewhat) Limited + Type Range
        12. +
        13. operator<< on a Value* now + prints the address of the object instead of its contents.
        14. +
        15. Bytecode Enhancements + Needed
        16. +
        17. [loopsimplify] Loop simplify is + really slow on 252.eon
        18. +
        19. [code-cleanup] SymbolTable class + cleanup, Type should not derive from Value, eliminate ConstantPointerRef + class.
        20. +
        21. The memory footprint of the LLVM IR has been reduced substantially.
        22. +
        23. The LLVM linker and many core classes have been sped up substantially.
        24. +
        + +
        + + +
        + In this release, the following build problems were fixed: +
        + + + + + + +
        +
          +
        1. Fixed: [vmcore] Code quality problem + due to long operand of getelementptr
        2. + +
        3. The X86 backend now generates substantially better code for 64-bit integer + and floating point operations.
        4. + +
        5. The -inline pass no longer inlines mutually recursive functions until it + hits the inlining threshold.
        6. + +
        7. The -inline pass no longer misses obvious inlining opportunities just + because the callee eventually calls into an external function.
        8. + +
        9. The -simplifycfg pass can now "if convert" simple statements into the + select instruction.
        10. + +
        11. The -loopsimplify pass can now break natural loops with multiple backedges + into multiple nested loops. This enables a variety of subsequent + optimizations.
        12. + +
        13. The -adce pass can now eliminate calls to functions that do not not write to + memory.
        14. + +
        15. The link-time optimizer now runs the -prune-eh pass (to remove unused + exception handlers).
        16. + +
        17. The link-time optimizer now runs dead store elimination and uses a simple + interprocedural alias analysis.
        18. + +
        19. The -simplifycfg pass can now eliminate simple correlated branches (such as + "if (A < B && A < B)", and can turn short-circuiting + operators into the strict versions when useful (such as "if (A < B || A + > C)" into "if (A < B | A > C)"
        20. + +
        21. LLVM now has infrastructure for (simple and sparse conditional) constant + propagation of function calls. It currently supports a few math library + functions like sqrt/sin/cos/etc.
        22. + +
        23. The C backend now emits syntactic + loops in the code to help C compilers whose optimizers do not recognize + loops formed from gotos (like GCC).
        24. + +
        25. The SparcV9 backend no longers spills the null constant to the constant + pool.
        26. +
        +
        + + + + + + + + + + +
        + +

        LLVM is known to work in the following platforms:

        + +
          +
        • Intel and AMD machines running Red Hat Linux and FreeBSD (and probably + other unix-like systems).
        • +
        • Sun UltraSPARC workstations running Solaris 8.
        • +
        • Intel and AMD machines running on Win32 with the Cygwin libraries.
        • +
        • PowerPC-based Mac OS X boxes, running 10.2 and above. Note that no JIT + support is available yet, and LLC support is beta. The C backend can be used + to produce stable code for this platform.
        • +
        + +

        The core LLVM infrastructure uses + GNU autoconf to adapt itself + to the machine and operating system on which it is built. However, minor + porting may be required to get LLVM to work on new platforms. We welcome your + portability patches and reports of successful builds or error messages.

        + +

        Note that the LLVM build system does not currently support directories with + spaces on them when running on Win32/cygwin. We strongly recommend running + LLVM and the C frontend out of a top-level directory without spaces (e.g., + /cygdrive/c/llvm). Also, make sure to install all of the + cygwin packages. By default, many important tools are not installed that + are needed by the LLVM build process or test suite (e.g., /bin/time).

        + +
        + + + + + +
        + +

        This section contains all known problems with the LLVM system, listed by + component. As new problems are discovered, they will be added to these + sections. If you run into a problem, please check the LLVM bug database and submit a bug if + there isn't already one.

        + +
        + + + + +
        + +

        The following components of this LLVM release are either untested, known to + be broken or unreliable, or are in early development. These components should + not be relied on, and bugs should not be filed against them, but they may be + useful to some people. In particular, if you would like to work on one of these + components, please contact us on the llvmdev list.

        + +
          +
        • The PowerPC backend is incomplete and is known to miscompile several SPEC + benchmarks. The file llvm/lib/Target/PowerPC/README.txt has + details.
        • +
        • The following passes are incomplete or buggy: -pgmdep, -memdep, + -ipmodref, -cee
        • +
        • The -pre pass is incomplete (there are cases it doesn't handle that + it should) and not thoroughly tested.
        • +
        • The llvm-ar tool is incomplete and probably buggy.
        • +
        • The llvm-db tool is in a very early stage of development.
        • +
        + +
        + + + + +
        + + +
        + + + + + +
        Bugs
        + +
        + +
        + + +
        + Notes +
        + +
        + +
          + +
        • Inline assembly is not yet supported.
        • + +
        • "long double" is transformed by the front-end into "double". There is no + support for floating point data types of any size other than 32 and 64 + bits.
        • + +
        • The following Unix system functionality has not been tested and may not + work: +
            +
          1. sigsetjmp, siglongjmp - These are not turned into the + appropriate invoke/unwind instructions. Note that + setjmp and longjmp are compiled correctly. +
          2. getcontext, setcontext, makecontext + - These functions have not been tested. +
        • + +
        • Although many GCC extensions are supported, some are not. In particular, + the following extensions are known to not be supported: +
            +
          1. Local Labels: Labels local to a block.
          2. +
          3. Nested Functions: As in Algol and Pascal, lexical scoping of functions.
          4. +
          5. Constructing Calls: Dispatching a call to another function.
          6. +
          7. Extended Asm: Assembler instructions with C expressions as operands.
          8. +
          9. Constraints: Constraints for asm operands.
          10. +
          11. Asm Labels: Specifying the assembler name to use for a C symbol.
          12. +
          13. Explicit Reg Vars: Defining variables residing in specified registers.
          14. +
          15. Vector Extensions: Using vector instructions through built-in functions.
          16. +
          17. Target Builtins: Built-in functions specific to particular targets.
          18. +
          19. Thread-Local: Per-thread variables.
          20. +
          21. Pragmas: Pragmas accepted by GCC.
          22. +
          + +

          The following GCC extensions are partially supported. An ignored + attribute means that the LLVM compiler ignores the presence of the attribute, + but the code should still work. An unsupported attribute is one which is + ignored by the LLVM compiler and will cause a different interpretation of + the program.

          + +
            +
          1. Variable Length: + Arrays whose length is computed at run time.
            + Supported, but allocated stack space is not freed until the function returns (noted above).
          2. + +
          3. Function Attributes: + + Declaring that functions have no side effects or that they can never + return.
            + + Supported: format, format_arg, non_null, + constructor, destructor, unused, + deprecated, warn_unused_result, weak
            + + Ignored: noreturn, noinline, + always_inline, pure, const, nothrow, + malloc, no_instrument_function, cdecl
            + + Unsupported: used, section, alias, + visibility, regparm, stdcall, + fastcall, all other target specific attributes
          4. + +
          5. Variable Attributes: + Specifying attributes of variables.
            + Supported: cleanup, common, nocommon, + deprecated, transparent_union, + unused, weak
            + + Unsupported: aligned, mode, packed, + section, shared, tls_model, + vector_size, dllimport, + dllexport, all target specific attributes.
          6. + +
          7. Type Attributes: Specifying attributes of types.
            + Supported: transparent_union, unused, + deprecated, may_alias
            + + Unsupported: aligned, packed, + all target specific attributes.
          8. + +
          9. Other Builtins: + Other built-in functions.
            + We support all builtins which have a C language equivalent (e.g., + __builtin_cos), __builtin_alloca, + __builtin_types_compatible_p, __builtin_choose_expr, + __builtin_constant_p, and __builtin_expect + (currently ignored). We also support builtins for ISO C99 floating + point comparison macros (e.g., __builtin_islessequal).
          10. +
          + +

          The following extensions are known to be supported:

          + +
            +
          1. Labels as Values: Getting pointers to labels and computed gotos.
          2. +
          3. Statement Exprs: Putting statements and declarations inside expressions.
          4. +
          5. Typeof: typeof: referring to the type of an expression.
          6. +
          7. Lvalues: Using ?:, "," and casts in lvalues.
          8. +
          9. Conditionals: Omitting the middle operand of a ?: expression.
          10. +
          11. Long Long: Double-word integers.
          12. +
          13. Complex: Data types for complex numbers.
          14. +
          15. Hex Floats:Hexadecimal floating-point constants.
          16. +
          17. Zero Length: Zero-length arrays.
          18. +
          19. Empty Structures: Structures with no members.
          20. +
          21. Variadic Macros: Macros with a variable number of arguments.
          22. +
          23. Escaped Newlines: Slightly looser rules for escaped newlines.
          24. +
          25. Subscripting: Any array can be subscripted, even if not an lvalue.
          26. +
          27. Pointer Arith: Arithmetic on void-pointers and function pointers.
          28. +
          29. Initializers: Non-constant initializers.
          30. +
          31. Compound Literals: Compound literals give structures, unions, + or arrays as values.
          32. +
          33. Designated Inits: Labeling elements of initializers.
          34. +
          35. Cast to Union: Casting to union type from any member of the union.
          36. +
          37. Case Ranges: `case 1 ... 9' and such.
          38. +
          39. Mixed Declarations: Mixing declarations and code.
          40. +
          41. Function Prototypes: Prototype declarations and old-style definitions.
          42. +
          43. C++ Comments: C++ comments are recognized.
          44. +
          45. Dollar Signs: Dollar sign is allowed in identifiers.
          46. +
          47. Character Escapes: \e stands for the character <ESC>.
          48. +
          49. Alignment: Inquiring about the alignment of a type or variable.
          50. +
          51. Inline: Defining inline functions (as fast as macros).
          52. +
          53. Alternate Keywords:__const__, __asm__, etc., for header files.
          54. +
          55. Incomplete Enums: enum foo;, with details to follow.
          56. +
          57. Function Names: Printable strings which are the name of the current function.
          58. +
          59. Return Address: Getting the return or frame address of a function.
          60. +
          61. Unnamed Fields: Unnamed struct/union fields within structs/unions.
          62. +
          63. Attribute Syntax: Formal syntax for attributes.
          64. +
        • + +
        + +

        If you run into GCC extensions which have not been included in any of these + lists, please let us know (also including whether or not they work).

        + +
        + + + + +
        + +

        For this release, the C++ front-end is considered to be fully functional but + has not been tested as thoroughly as the C front-end. It has been tested and + works for a number of non-trivial programs, but there may be lurking bugs. + Please report any bugs or problems.

        + +
        + + +
        Bugs
        + +
        + +
          +
        • The C++ front-end inherits all problems afflicting the C + front-end.
        • + +
        • IA-64 specific: The C++ front-end does not use IA64 ABI compliant layout of v-tables. + In particular, it just stores function pointers instead of function + descriptors in the vtable. This bug prevents mixing C++ code compiled with + LLVM with C++ objects compiled by other C++ compilers.
        • + +
        + +
        + + +
        + Notes +
        + +
        + +
          + +
        • The C++ front-end is based on a pre-release of the GCC 3.4 C++ parser. This + parser is significantly more standards compliant (and picky) than prior GCC + versions. For more information, see the C++ section of the GCC 3.4 release notes.
        • + +
        • Destructors for local objects are not always run when a longjmp is + performed. In particular, destructors for objects in the longjmping + function and in the setjmp receiver function may not be run. + Objects in intervening stack frames will be destroyed, however (which is + better than most compilers).
        • + +
        • The LLVM C++ front-end follows the Itanium C++ ABI. + This document, which is not Itanium specific, specifies a standard for name + mangling, class layout, v-table layout, RTTI formats, and other C++ + representation issues. Because we use this API, code generated by the LLVM + compilers should be binary compatible with machine code generated by other + Itanium ABI C++ compilers (such as G++, the Intel and HP compilers, etc). + However, the exception handling mechanism used by LLVM is very + different from the model used in the Itanium ABI, so exceptions will not + interact correctly.
        • + +
        + +
        + + + + +
        + +
          +
        • none yet
        • +
        + +
        + + + + + + + + + +
        + +
          + +
        • The C back-end produces code that violates the ANSI C Type-Based Alias + Analysis rules. As such, special options may be necessary to compile the code + (for example, GCC requires the -fno-strict-aliasing option). This + problem probably cannot be fixed.
        • + +
        • Initializers for global variables + cannot include special floating point numbers like Not-A-Number or + Infinity.
        • + +
        • Zero arg vararg functions are not + supported. This should not affect LLVM produced by the C or C++ + frontends.
        • + +
        + +
        + + + + + +
        + +

        A wide variety of additional information is available on the LLVM web page, + including mailing lists and publications describing algorithms and components + implemented in LLVM. The web page also contains versions of the API + documentation which is up-to-date with the CVS version of the source code. You + can access versions of these documents specific to this release by going into + the "llvm/doc/" directory in the LLVM tree.

        + +

        If you have any questions or comments about LLVM, please feel free to contact + us via the mailing + lists.

        + +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + The LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:04 $ +
        + + + Index: llvm-www/releases/1.3/docs/SourceLevelDebugging.html diff -c /dev/null llvm-www/releases/1.3/docs/SourceLevelDebugging.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/SourceLevelDebugging.html Fri Aug 13 17:03:04 2004 *************** *** 0 **** --- 1,1118 ---- + + + + Source Level Debugging with LLVM + + + + +
        Source Level Debugging with LLVM
        + + + + + + +
        + + + A leafy and green bug eater +
        + +
        +

        Written by Chris Lattner

        +
        + + + + + +
        + +

        This document is the central repository for all information pertaining to + debug information in LLVM. It describes the user + interface for the llvm-db tool, which provides a + powerful source-level debugger + to users of LLVM-based compilers. It then describes the various components that make up the debugger and the + libraries which future clients may use. Finally, it describes the actual format that the LLVM debug information takes, + which is useful for those interested in creating front-ends or dealing directly + with the information.

        + +
        + + + + +
        + +

        The idea of the LLVM debugging information is to capture how the important + pieces of the source-language's Abstract Syntax Tree map onto LLVM code. + Several design aspects have shaped the solution that appears here. The + important ones are:

        + +
          +
        • Debugging information should have very little impact on the rest of the + compiler. No transformations, analyses, or code generators should need to be + modified because of debugging information.
        • + +
        • LLVM optimizations should interact in well-defined and + easily described ways with the debugging information.
        • + +
        • Because LLVM is designed to support arbitrary programming languages, + LLVM-to-LLVM tools should not need to know anything about the semantics of the + source-level-language.
        • + +
        • Source-level languages are often widely different from one another. + LLVM should not put any restrictions of the flavor of the source-language, and + the debugging information should work with any language.
        • + +
        • With code generator support, it should be possible to use an LLVM compiler + to compile a program to native machine code and standard debugging formats. + This allows compatibility with traditional machine-code level debuggers, like + GDB or DBX.
        • + +
        + +

        The approach used by the LLVM implementation is to use a small set of intrinsic functions to define a mapping + between LLVM program objects and the source-level objects. The description of + the source-level program is maintained in LLVM global variables in an implementation-defined format (the C/C++ front-end + currently uses working draft 7 of the Dwarf 3 standard).

        + +

        When a program is debugged, the debugger interacts with the user and turns + the stored debug information into source-language specific information. As + such, the debugger must be aware of the source-language, and is thus tied to a + specific language of family of languages. The LLVM + debugger is designed to be modular in its support for source-languages.

        + +
        + + + + + +
        + +

        An extremely high priority of LLVM debugging information is to make it + interact well with optimizations and analysis. In particular, the LLVM debug + information provides the following guarantees:

        + +
          + +
        • LLVM debug information always provides information to accurately read the + source-level state of the program, regardless of which LLVM optimizations + have been run, and without any modification to the optimizations themselves. + However, some optimizations may impact the ability to modify the current state + of the program with a debugger, such as setting program variables, or calling + function that have been deleted.
        • + +
        • LLVM optimizations gracefully interact with debugging information. If they + are not aware of debug information, they are automatically disabled as necessary + in the cases that would invalidate the debug info. This retains the LLVM + features making it easy to write new transformations.
        • + +
        • As desired, LLVM optimizations can be upgraded to be aware of the LLVM + debugging information, allowing them to update the debugging information as they + perform aggressive optimizations. This means that, with effort, the LLVM + optimizers could optimize debug code just as well as non-debug code.
        • + +
        • LLVM debug information does not prevent many important optimizations from + happening (for example inlining, basic block reordering/merging/cleanup, tail + duplication, etc), further reducing the amount of the compiler that eventually + is "aware" of debugging information.
        • + +
        • LLVM debug information is automatically optimized along with the rest of the + program, using existing facilities. For example, duplicate information is + automatically merged by the linker, and unused information is automatically + removed.
        • + +
        + +

        Basically, the debug information allows you to compile a program with + "-O0 -g" and get full debug information, allowing you to arbitrarily + modify the program as it executes from the debugger. Compiling a program with + "-O3 -g" gives you full debug information that is always available and + accurate for reading (e.g., you get accurate stack traces despite tail call + elimination and inlining), but you might lose the ability to modify the program + and call functions where were optimized out of the program, or inlined away + completely.

        + +
        + + + + +
        +

        There are several important extensions that could be eventually added to the + LLVM debugger. The most important extension would be to upgrade the LLVM code + generators to support debugging information. This would also allow, for + example, the X86 code generator to emit native objects that contain debugging + information consumable by traditional source-level debuggers like GDB or + DBX.

        + +

        Additionally, LLVM optimizations can be upgraded to incrementally update the + debugging information, new commands can be added to the + debugger, and thread support could be added to the debugger.

        + +

        The "SourceLanguage" modules provided by llvm-db could be + substantially improved to provide good support for C++ language features like + namespaces and scoping rules.

        + +

        After working with the debugger for a while, perhaps the nicest improvement + would be to add some sort of line editor, such as GNU readline (but one that is + compatible with the LLVM license).

        + +

        For someone so inclined, it should be straight-forward to write different + front-ends for the LLVM debugger, as the LLVM debugging engine is cleanly + separated from the llvm-db front-end. A new LLVM GUI debugger or IDE + would be nice. :)

        + +
        + + + + + +
        + +

        The llvm-db tool provides a GDB-like interface for source-level + debugging of programs. This tool provides many standard commands for inspecting + and modifying the program as it executes, loading new programs, single stepping, + placing breakpoints, etc. This section describes how to use the debugger.

        + +

        llvm-db has been designed to be as similar to GDB in its user + interface as possible. This should make it extremely easy to learn + llvm-db if you already know GDB. In general, llvm-db + provides the subset of GDB commands that are applicable to LLVM debugging users. + If there is a command missing that make a reasonable amount of sense within the + limitations of llvm-db, please report it as + a bug or, better yet, submit a patch to add it. :)

        + +
        + + + + +
        + +

        llvm-db is designed to be modular and easy to extend. This + extensibility was key to getting the debugger up-and-running quickly, because we + can start with simple-but-unsophisicated implementations of various components. + Because of this, it is currently missing many features, though they should be + easy to add over time (patches welcomed!). The biggest inherent limitations of + llvm-db are currently due to extremely simple debugger backend (implemented in + "lib/Debugger/UnixLocalInferiorProcess.cpp") which is designed to work without + any cooperation from the code generators. Because it is so simple, it suffers + from the following inherent limitations:

        + +
          + +
        • Running a program in llvm-db is a bit slower than running it with + lli (i.e., in the JIT).
        • + +
        • Inspection of the target hardware is not supported. This means that you + cannot, for example, print the contents of X86 registers.
        • + +
        • Inspection of LLVM code is not supported. This means that you cannot print + the contents of arbitrary LLVM values, or use commands such as stepi. + This also means that you cannot debug code without debug information.
        • + +
        • Portions of the debugger run in the same address space as the program being + debugged. This means that memory corruption by the program could trample on + portions of the debugger.
        • + +
        • Attaching to existing processes and core files is not currently + supported.
        • + +
        + +

        That said, the debugger is still quite useful, and all of these limitations + can be eliminated by integrating support for the debugger into the code + generators, and writing a new InferiorProcess + subclass to use it. See the future work section for ideas + of how to extend the LLVM debugger despite these limitations.

        + +
        + + + + + +
        + +

        TODO: this is obviously lame, when more is implemented, this can be much + better.

        + +
        + $ llvm-db funccall
        + llvm-db: The LLVM source-level debugger
        + Loading program... successfully loaded 'funccall.bc'!
        + (llvm-db) create
        + Starting program: funccall.bc
        + main at funccall.c:9:2
        + 9 ->            q = 0;
        + (llvm-db) list main
        + 4       void foo() {
        + 5               int t = q;
        + 6               q = t + 1;
        + 7       }
        + 8       int main() {
        + 9 ->            q = 0;
        + 10              foo();
        + 11              q = q - 1;
        + 12
        + 13              return q;
        + (llvm-db) list
        + 14      }
        + (llvm-db) step
        + 10 ->           foo();
        + (llvm-db) s
        + foo at funccall.c:5:2
        + 5 ->            int t = q;
        + (llvm-db) bt
        + #0 ->   0x85ffba0 in foo at funccall.c:5:2
        + #1      0x85ffd98 in main at funccall.c:10:2
        + (llvm-db) finish
        + main at funccall.c:11:2
        + 11 ->           q = q - 1;
        + (llvm-db) s
        + 13 ->           return q;
        + (llvm-db) s
        + The program stopped with exit code 0
        + (llvm-db) quit
        + $
        + 
        + +
        + + + + + + +
        + +

        There are three ways to start up the llvm-db debugger:

        + +

        When run with no options, just llvm-db, the debugger starts up + without a program loaded at all. You must use the file command to load a program, and the set args or run + commands to specify the arguments for the program.

        + +

        If you start the debugger with one argument, as llvm-db + <program>, the debugger will start up and load in the specified + program. You can then optionally specify arguments to the program with the set args or run + commands.

        + +

        The third way to start the program is with the --args option. This + option allows you to specify the program to load and the arguments to start out + with. Example use: llvm-db --args ls /home

        + +
        + + + + +
        + +

        FIXME: this needs work obviously. See the GDB documentation for + information about what these do, or try 'help [command]' within + llvm-db to get information.

        + +

        +

        General usage:

        +
          +
        • help [command]
        • +
        • quit
        • +
        • file [program]
        • +
        + +

        Program inspection and interaction:

        +
          +
        • create (start the program, stopping it ASAP in main)
        • +
        • kill
        • +
        • run [args]
        • +
        • step [num]
        • +
        • next [num]
        • +
        • cont
        • +
        • finish
        • + +
        • list [start[, end]]
        • +
        • info source
        • +
        • info sources
        • +
        • info functions
        • +
        + +

        Call stack inspection:

        +
          +
        • backtrace
        • +
        • up [n]
        • +
        • down [n]
        • +
        • frame [n]
        • +
        + + +

        Debugger inspection and interaction:

        +
          +
        • info target
        • +
        • show prompt
        • +
        • set prompt
        • +
        • show listsize
        • +
        • set listsize
        • +
        • show language
        • +
        • set language
        • +
        • show args
        • +
        • set args [args]
        • +
        + +

        TODO:

        +
          +
        • info frame
        • +
        • break
        • +
        • print
        • +
        • ptype
        • + +
        • info types
        • +
        • info variables
        • +
        • info program
        • + +
        • info args
        • +
        • info locals
        • +
        • info catch
        • +
        • ... many others
        • +
        + +
        + + + + + +
        +

        The LLVM debugger is built out of three distinct layers of software. These + layers provide clients with different interface options depending on what pieces + of they want to implement themselves, and it also promotes code modularity and + good design. The three layers are the Debugger + interface, the "info" interfaces, and the llvm-db tool itself.

        +
        + + + + +
        +

        The Debugger class (defined in the include/llvm/Debugger/ directory) + is a low-level class which is used to maintain information about the loaded + program, as well as start and stop the program running as necessary. This class + does not provide any high-level analysis or control over the program, only + exposing simple interfaces like load/unloadProgram, + create/killProgram, step/next/finish/contProgram, and + low-level methods for installing breakpoints.

        + +

        + The Debugger class is itself a wrapper around the lowest-level InferiorProcess + class. This class is used to represent an instance of the program running under + debugger control. The InferiorProcess class can be implemented in different + ways for different targets and execution scenarios (e.g., remote debugging). + The InferiorProcess class exposes a small and simple collection of interfaces + which are useful for inspecting the current state of the program (such as + collecting stack trace information, reading the memory image of the process, + etc). The interfaces in this class are designed to be as low-level and simple + as possible, to make it easy to create new instances of the class. +

        + +

        + The Debugger class exposes the currently active instance of InferiorProcess + through the Debugger::getRunningProcess method, which returns a + const reference to the class. This means that clients of the Debugger + class can only inspect the running instance of the program directly. To + change the executing process in some way, they must use the interces exposed by + the Debugger class. +

        +
        + + + + +
        +

        + The next-highest level of debugger abstraction is provided through the + ProgramInfo, RuntimeInfo, SourceLanguage and related classes (also defined in + the include/llvm/Debugger/ directory). These classes efficiently + decode the debugging information and low-level interfaces exposed by + InferiorProcess into a higher-level representation, suitable for analysis by the + debugger. +

        + +

        + The ProgramInfo class exposes a variety of different kinds of information about + the program objects in the source-level-language. The SourceFileInfo class + represents a source-file in the program (e.g. a .cpp or .h file). The + SourceFileInfo class captures information such as which SourceLanguage was used + to compile the file, where the debugger can get access to the actual file text + (which is lazily loaded on demand), etc. The SourceFunctionInfo class + represents a... FIXME: finish. The ProgramInfo class provides interfaces + to lazily find and decode the information needed to create the Source*Info + classes requested by the debugger. +

        + +

        + The RuntimeInfo class exposes information about the currently executed program, + by decoding information from the InferiorProcess and ProgramInfo classes. It + provides a StackFrame class which provides an easy-to-use interface for + inspecting the current and suspended stack frames in the program. +

        + +

        + The SourceLanguage class is an abstract interface used by the debugger to + perform all source-language-specific tasks. For example, this interface is used + by the ProgramInfo class to decode language-specific types and functions and by + the debugger front-end (such as llvm-db to + evaluate source-langauge expressions typed into the debugger. This class uses + the RuntimeInfo & ProgramInfo classes to get information about the current + execution context and the loaded program, respectively. +

        + +
        + + + + +
        +

        + The llvm-db is designed to be a debugger providing an interface as similar to GDB as reasonable, but no more so than that. + Because the Debugger and info classes implement all of the heavy lifting and + analysis, llvm-db (which lives in llvm/tools/llvm-db) consists + mainly of of code to interact with the user and parse commands. The CLIDebugger + constructor registers all of the builtin commands for the debugger, and each + command is implemented as a CLIDebugger::[name]Command method. +

        +
        + + + + + +
        + +

        + FIXME: this section will eventually go away. These are notes to myself of + things that should be implemented, but haven't yet. +

        + +

        + Breakpoints: Support is already implemented in the 'InferiorProcess' + class, though it hasn't been tested yet. To finish breakpoint support, we need + to implement breakCommand (which should reuse the linespec parser from the list + command), and handle the fact that 'break foo' or 'break file.c:53' may insert + multiple breakpoints. Also, if you say 'break file.c:53' and there is no + stoppoint on line 53, the breakpoint should go on the next available line. My + idea was to have the Debugger class provide a "Breakpoint" class which + encapsulated this messiness, giving the debugger front-end a simple interface. + The debugger front-end would have to map the really complex semantics of + temporary breakpoints and 'conditional' breakpoints onto this intermediate + level. Also, breakpoints should survive as much as possible across program + reloads. +

        + +

        + UnixLocalInferiorProcess.cpp speedup: There is no reason for the debugged + process to code gen the globals corresponding to debug information. The + IntrinsicLowering object could instead change descriptors into constant expr + casts of the constant address of the LLVM objects for the descriptors. This + would also allow us to eliminate the mapping back and forth between physical + addresses that must be done.

        + +

        + Process deaths: The InferiorProcessDead exception should be extended to + know "how" a process died, i.e., it was killed by a signal. This is easy to + collect in the UnixLocalInferiorProcess, we just need to represent it.

        + +
        + + + + + +
        + +

        LLVM debugging information has been carefully designed to make it possible + for the optimizer to optimize the program and debugging information without + necessarily having to know anything about debugging information. In particular, + the global constant merging pass automatically eliminates duplicated debugging + information (often caused by header files), the global dead code elimination + pass automatically deletes debugging information for a function if it decides to + delete the function, and the linker eliminates debug information when it merges + linkonce functions.

        + +

        To do this, most of the debugging information (descriptors for types, + variables, functions, source files, etc) is inserted by the language front-end + in the form of LLVM global variables. These LLVM global variables are no + different from any other global variables, except that they have a web of LLVM + intrinsic functions that point to them. If the last references to a particular + piece of debugging information are deleted (for example, by the + -globaldce pass), the extraneous debug information will automatically + become dead and be removed by the optimizer.

        + +

        The debugger is designed to be agnostic about the contents of most of the + debugging information. It uses a source-language-specific + module to decode the information that represents variables, types, + functions, namespaces, etc: this allows for arbitrary source-language semantics + and type-systems to be used, as long as there is a module written for the + debugger to interpret the information.

        + +

        To provide basic functionality, the LLVM debugger does have to make some + assumptions about the source-level language being debugged, though it keeps + these to a minimum. The only common features that the LLVM debugger assumes + exist are source files, and program objects. These abstract objects are + used by the debugger to form stack traces, show information about local + variables, etc.

        + +

        This section of the documentation first describes the representation aspects + common to any source-language. The next section + describes the data layout conventions used by the C and C++ front-ends.

        + +
        + + + + +
        +

        One important aspect of the LLVM debug representation is that it allows the + LLVM debugger to efficiently index all of the global objects without having the + scan the program. To do this, all of the global objects use "anchor" globals of + type "{}", with designated names. These anchor objects obviously do + not contain any content or meaning by themselves, but all of the global objects + of a particular type (e.g., source file descriptors) contain a pointer to the + anchor. This pointer allows the debugger to use def-use chains to find all + global objects of that type.

        + +

        So far, the following names are recognized as anchors by the LLVM + debugger:

        + +
        +   %llvm.dbg.translation_units = linkonce global {} {}
        +   %llvm.dbg.globals         = linkonce global {} {}
        + 
        + +

        Using anchors in this way (where the source file descriptor points to the + anchors, as opposed to having a list of source file descriptors) allows for the + standard dead global elimination and merging passes to automatically remove + unused debugging information. If the globals were kept track of through lists, + there would always be an object pointing to the descriptors, thus would never be + deleted.

        + +
        + + + + +
        + +

        LLVM debugger "stop points" are a key part of the debugging representation + that allows the LLVM to maintain simple semantics for debugging optimized code. The basic idea is that the + front-end inserts calls to the %llvm.dbg.stoppoint intrinsic function + at every point in the program where the debugger should be able to inspect the + program (these correspond to places the debugger stops when you "step" + through it). The front-end can choose to place these as fine-grained as it + would like (for example, before every subexpression evaluated), but it is + recommended to only put them after every source statement that includes + executable code.

        + +

        Using calls to this intrinsic function to demark legal points for the + debugger to inspect the program automatically disables any optimizations that + could potentially confuse debugging information. To non-debug-information-aware + transformations, these calls simply look like calls to an external function, + which they must assume to do anything (including reading or writing to any part + of reachable memory). On the other hand, it does not impact many optimizations, + such as code motion of non-trapping instructions, nor does it impact + optimization of subexpressions, code duplication transformations, or basic-block + reordering transformations.

        + +

        An important aspect of the calls to the %llvm.dbg.stoppoint + intrinsic is that the function-local debugging information is woven together + with use-def chains. This makes it easy for the debugger to, for example, + locate the 'next' stop point. For a concrete example of stop points, see the + example in the next section.

        + +
        + + + + + +
        +

        In many languages, the local variables in functions can have their lifetime + or scope limited to a subset of a function. In the C family of languages, for + example, variables are only live (readable and writable) within the source block + that they are defined in. In functional languages, values are only readable + after they have been defined. Though this is a very obvious concept, it is also + non-trivial to model in LLVM, because it has no notion of scoping in this sense, + and does not want to be tied to a language's scoping rules.

        + +

        In order to handle this, the LLVM debug format uses the notion of "regions" + of a function, delineated by calls to intrinsic functions. These intrinsic + functions define new regions of the program and indicate when the region + lifetime expires. Consider the following C fragment, for example:

        + +
        + 1.  void foo() {
        + 2.    int X = ...;
        + 3.    int Y = ...;
        + 4.    {
        + 5.      int Z = ...;
        + 6.      ...
        + 7.    }
        + 8.    ...
        + 9.  }
        + 
        + +

        Compiled to LLVM, this function would be represented like this (FIXME: CHECK + AND UPDATE THIS):

        + +
        + void %foo() {
        +     %X = alloca int
        +     %Y = alloca int
        +     %Z = alloca int
        +     %D1 = call {}* %llvm.dbg.func.start(%lldb.global* %d.foo)
        +     %D2 = call {}* %llvm.dbg.stoppoint({}* %D1, uint 2, uint 2, %lldb.compile_unit* %file)
        + 
        +     %D3 = call {}* %llvm.dbg.DEFINEVARIABLE({}* %D2, ...)
        +     ;; Evaluate expression on line 2, assigning to X.
        +     %D4 = call {}* %llvm.dbg.stoppoint({}* %D3, uint 3, uint 2, %lldb.compile_unit* %file)
        + 
        +     %D5 = call {}* %llvm.dbg.DEFINEVARIABLE({}* %D4, ...)
        +     ;; Evaluate expression on line 3, assigning to Y.
        +     %D6 = call {}* %llvm.dbg.stoppoint({}* %D5, uint 5, uint 4, %lldb.compile_unit* %file)
        + 
        +     %D7 = call {}* %llvm.region.start({}* %D6)
        +     %D8 = call {}* %llvm.dbg.DEFINEVARIABLE({}* %D7, ...)
        +     ;; Evaluate expression on line 5, assigning to Z.
        +     %D9 = call {}* %llvm.dbg.stoppoint({}* %D8, uint 6, uint 4, %lldb.compile_unit* %file)
        + 
        +     ;; Code for line 6.
        +     %D10 = call {}* %llvm.region.end({}* %D9)
        +     %D11 = call {}* %llvm.dbg.stoppoint({}* %D10, uint 8, uint 2, %lldb.compile_unit* %file)
        + 
        +     ;; Code for line 8.
        +     %D12 = call {}* %llvm.region.end({}* %D11)
        +     ret void
        + }
        + 
        + +

        This example illustrates a few important details about the LLVM debugging + information. In particular, it shows how the various intrinsics used are woven + together with def-use and use-def chains, similar to how anchors are used with globals. This allows + the debugger to analyze the relationship between statements, variable + definitions, and the code used to implement the function.

        + +

        In this example, two explicit regions are defined, one with the definition of the %D1 variable and one with the + definition of %D7. In the case of + %D1, the debug information indicates that the function whose descriptor is specified as an argument to the + intrinsic. This defines a new stack frame whose lifetime ends when the region + is ended by the %D12 call.

        + +

        Using regions to represent the boundaries of source-level functions allow + LLVM interprocedural optimizations to arbitrarily modify LLVM functions without + having to worry about breaking mapping information between the LLVM code and the + and source-level program. In particular, the inliner requires no modification + to support inlining with debugging information: there is no explicit correlation + drawn between LLVM functions and their source-level counterparts (note however, + that if the inliner inlines all instances of a non-strong-linkage function into + its caller that it will not be possible for the user to manually invoke the + inlined function from the debugger).

        + +

        Once the function has been defined, the stopping point corresponding to line #2 of + the function is encountered. At this point in the function, no local + variables are live. As lines 2 and 3 of the example are executed, their + variable definitions are automatically introduced into the program, without the + need to specify a new region. These variables do not require new regions to be + introduced because they go out of scope at the same point in the program: line + 9.

        + +

        In contrast, the Z variable goes out of scope at a different time, + on line 7. For this reason, it is defined within the + %D7 region, which kills the availability of Z before the + code for line 8 is executed. In this way, regions can support arbitrary + source-language scoping rules, as long as they can only be nested (ie, one scope + cannot partially overlap with a part of another scope).

        + +

        It is worth noting that this scoping mechanism is used to control scoping of + all declarations, not just variable declarations. For example, the scope of a + C++ using declaration is controlled with this, and the llvm-db C++ + support routines could use this to change how name lookup is performed (though + this is not implemented yet).

        + +
        + + + + +
        +

        The LLVM debugger expects the descriptors for program objects to start in a + canonical format, but the descriptors can include additional information + appended at the end that is source-language specific. All LLVM debugging + information is versioned, allowing backwards compatibility in the case that the + core structures need to change in some way. Also, all debugging information + objects start with a tag to indicate what type + of object it is. The source-language is allows to define its own objects, by + using unreserved tag numbers.

        + +

        The lowest-level descriptor are those describing the files containing the program source + code, as most other descriptors (sometimes indirectly) refer to them. +

        +
        + + + + + +
        +

        + The LLVM debugger needs to know about some source-language program objects, in + order to build stack traces, print information about local variables, and other + related activities. The LLVM debugger differentiates between three different + types of program objects: subprograms (functions, messages, methods, etc), + variables (locals and globals), and others. Because source-languages have + widely varying forms of these objects, the LLVM debugger expects only a few + fields in the descriptor for each object: +

        + +
        + %lldb.object = type {
        +        uint,                  ;; A tag
        +        any*,                  ;; The context for the object
        +        sbyte*                 ;; The object 'name'
        + }
        + 
        + +

        The first field contains a tag for the descriptor. The second field contains + either a pointer to the descriptor for the containing source file, or it contains a pointer to + another program object whose context pointer eventually reaches a source file. + Through this context pointer, the + LLVM debugger can establish the debug version number of the object.

        + +

        The third field contains a string that the debugger can use to identify the + object if it does not contain explicit support for the source-language in use + (ie, the 'unknown' source language handler uses this string). This should be + some sort of unmangled string that corresponds to the object, but it is a + quality of implementation issue what exactly it contains (it is legal, though + not useful, for all of these strings to be null).

        + +

        Note again that descriptors can be extended to include + source-language-specific information in addition to the fields required by the + LLVM debugger. See the section on the C/C++ + front-end for more information. Also remember that global objects + (functions, selectors, global variables, etc) must contain an anchor to the llvm.dbg.globals + variable.

        +
        + + + + + +
        +
        + Allow source-language specific contexts, use to identify namespaces etc
        + Must end up in a source file descriptor.
        + Debugger core ignores all unknown context objects.
        + 
        +
        + + + + +
        +
        + Define each intrinsics, as an extension of the language reference manual.
        + 
        + llvm.dbg.stoppoint
        + llvm.dbg.region.start
        + llvm.dbg.region.end
        + llvm.dbg.function.start
        + llvm.dbg.declare
        + 
        +
        + + + + +
        + +

        Happen to be the same value as the similarly named Dwarf-3 tags, this may + change in the future.

        + +
        +   LLVM_COMPILE_UNIT     : 17
        +   LLVM_SUBPROGRAM       : 46
        +   LLVM_VARIABLE         : 52
        + 
        + 
        +
        + + + + + + +
        + +

        The C and C++ front-ends represent information about the program in a format + that is effectively identical to Dwarf 3.0 in terms of + information content. This allows code generators to trivially support native + debuggers by generating standard dwarf information, and contains enough + information for non-dwarf targets to translate it as needed.

        + +

        The basic debug information required by the debugger is (intentionally) + designed to be as minimal as possible. This basic information is so minimal + that it is unlikely that any source-language could be adequately + described by it. Because of this, the debugger format was designed for + extension to support source-language-specific information. The extended + descriptors are read and interpreted by the language-specific modules in the debugger if there is + support available, otherwise it is ignored.

        + +

        This section describes the extensions used to represent C and C++ programs. + Other languages could pattern themselves after this (which itself is tuned to + representing programs in the same way that Dwarf 3 does), or they could choose + to provide completely different extensions if they don't fit into the Dwarf + model. As support for debugging information gets added to the various LLVM + source-language front-ends, the information used should be documented here.

        + +
        + + + + +
        +

        TODO

        +
        + + + + +
        +

        + Translation units do not add any information over the standard source file representation already + expected by the debugger. As such, it uses descriptors of the type specified, + with a trailing anchor. +

        +
        + + + + +
        +

        TODO

        +
        + + + + +
        +

        TODO

        +
        + + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
        + LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:04 $ +
        + + + Index: llvm-www/releases/1.3/docs/Stacker.html diff -c /dev/null llvm-www/releases/1.3/docs/Stacker.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/Stacker.html Fri Aug 13 17:03:04 2004 *************** *** 0 **** --- 1,1414 ---- + + + + Stacker: An Example Of Using LLVM + + + + + +
        Stacker: An Example Of Using LLVM
        + +
          +
        1. Abstract
        2. +
        3. Introduction
        4. +
        5. Lessons I Learned About LLVM +
            +
          1. Everything's a Value!
          2. +
          3. Terminate Those Blocks!
          4. +
          5. Concrete Blocks
          6. +
          7. push_back Is Your Friend
          8. +
          9. The Wily GetElementPtrInst
          10. +
          11. Getting Linkage Types Right
          12. +
          13. Constants Are Easier Than That!
          14. +
        6. +
        7. The Stacker Lexicon +
            +
          1. The Stack
          2. +
          3. Punctuation
          4. +
          5. Comments
          6. +
          7. Literals
          8. +
          9. Words
          10. +
          11. Standard Style
          12. +
          13. Built-Ins
          14. +
        8. +
        9. Prime: A Complete Example
        10. +
        11. Internal Code Details +
            +
          1. The Directory Structure
          2. +
          3. The Lexer
          4. +
          5. The Parser
          6. +
          7. The Compiler
          8. +
          9. The Runtime
          10. +
          11. Compiler Driver
          12. +
          13. Test Programs
          14. +
          15. Exercise
          16. +
          17. Things Remaining To Be Done
          18. +
        12. +
        + +
        +

        Written by Reid Spencer

        +
        + + + +
        +

        This document is another way to learn about LLVM. Unlike the + LLVM Reference Manual or + LLVM Programmer's Manual, here we learn + about LLVM through the experience of creating a simple programming language + named Stacker. Stacker was invented specifically as a demonstration of + LLVM. The emphasis in this document is not on describing the + intricacies of LLVM itself but on how to use it to build your own + compiler system.

        +
        + + +
        +

        Amongst other things, LLVM is a platform for compiler writers. + Because of its exceptionally clean and small IR (intermediate + representation), compiler writing with LLVM is much easier than with + other system. As proof, I wrote the entire compiler (language definition, + lexer, parser, code generator, etc.) in about four days! + That's important to know because it shows how quickly you can get a new + language running when using LLVM. Furthermore, this was the first + language the author ever created using LLVM. The learning curve is + included in that four days.

        +

        The language described here, Stacker, is Forth-like. Programs + are simple collections of word definitions, and the only thing definitions + can do is manipulate a stack or generate I/O. Stacker is not a "real" + programming language; it's very simple. Although it is computationally + complete, you wouldn't use it for your next big project. However, + the fact that it is complete, it's simple, and it doesn't have + a C-like syntax make it useful for demonstration purposes. It shows + that LLVM could be applied to a wide variety of languages.

        +

        The basic notions behind stacker is very simple. There's a stack of + integers (or character pointers) that the program manipulates. Pretty + much the only thing the program can do is manipulate the stack and do + some limited I/O operations. The language provides you with several + built-in words that manipulate the stack in interesting ways. To get + your feet wet, here's how you write the traditional "Hello, World" + program in Stacker:

        +

        : hello_world "Hello, World!" >s DROP CR ;
        + : MAIN hello_world ;

        +

        This has two "definitions" (Stacker manipulates words, not + functions and words have definitions): MAIN and + hello_world. The MAIN definition is standard; it + tells Stacker where to start. Here, MAIN is defined to + simply invoke the word hello_world. The + hello_world definition tells stacker to push the + "Hello, World!" string on to the stack, print it out + (>s), pop it off the stack (DROP), and + finally print a carriage return (CR). Although + hello_world uses the stack, its net effect is null. Well + written Stacker definitions have that characteristic.

        +

        Exercise for the reader: how could you make this a one line program?

        +
        + +
        Lessons I Learned About LLVM
        +
        +

        Stacker was written for two purposes:

        +
          +
        1. to get the author over the learning curve, and
        2. +
        3. to provide a simple example of how to write a compiler using LLVM.
        4. +
        +

        During the development of Stacker, many lessons about LLVM were + learned. Those lessons are described in the following subsections.

        +

        + +
        Everything's a Value!
        +
        +

        Although I knew that LLVM uses a Single Static Assignment (SSA) format, + it wasn't obvious to me how prevalent this idea was in LLVM until I really + started using it. Reading the + Programmer's Manual and Language Reference, + I noted that most of the important LLVM IR (Intermediate Representation) C++ + classes were derived from the Value class. The full power of that simple + design only became fully understood once I started constructing executable + expressions for Stacker.

        + +

        This really makes your programming go faster. Think about compiling code + for the following C/C++ expression: (a|b)*((x+1)/(y+1)). Assuming + the values are on the stack in the order a, b, x, y, this could be + expressed in stacker as: 1 + SWAP 1 + / ROT2 OR *. + You could write a function using LLVM that computes this expression like + this:

        + +
        + Value* 
        + expression(BasicBlock* bb, Value* a, Value* b, Value* x, Value* y )
        + {
        +     ConstantSInt* one = ConstantSInt::get(Type::IntTy, 1);
        +     BinaryOperator* or1 = BinaryOperator::createOr(a, b, "", bb);
        +     BinaryOperator* add1 = BinaryOperator::createAdd(x, one, "", bb);
        +     BinaryOperator* add2 = BinaryOperator::createAdd(y, one, "", bb);
        +     BinaryOperator* div1 = BinaryOperator::createDiv(add1, add2, "", bb);
        +     BinaryOperator* mult1 = BinaryOperator::createMul(or1, div1, "", bb);
        +     return mult1;
        + }
        + 
        + +

        "Okay, big deal," you say? It is a big deal. Here's why. Note that I didn't + have to tell this function which kinds of Values are being passed in. They could be + Instructions, Constants, GlobalVariables, or + any of the other subclasses of Value that LLVM supports. + Furthermore, if you specify Values that are incorrect for this sequence of + operations, LLVM will either notice right away (at compilation time) or the LLVM + Verifier will pick up the inconsistency when the compiler runs. In either case + LLVM prevents you from making a type error that gets passed through to the + generated program. This really helps you write a compiler that + always generates correct code!

        +

        The second point is that we don't have to worry about branching, registers, + stack variables, saving partial results, etc. The instructions we create + are the values we use. Note that all that was created in the above + code is a Constant value and five operators. Each of the instructions is + the resulting value of that instruction. This saves a lot of time.

        +

        The lesson is this: SSA form is very powerful: there is no difference + between a value and the instruction that created it. This is fully + enforced by the LLVM IR. Use it to your best advantage.

        +
        + +
        Terminate Those Blocks!
        +
        +

        I had to learn about terminating blocks the hard way: using the debugger + to figure out what the LLVM verifier was trying to tell me and begging for + help on the LLVMdev mailing list. I hope you avoid this experience.

        +

        Emblazon this rule in your mind:

        +
          +
        • All BasicBlocks in your compiler must be + terminated with a terminating instruction (branch, return, etc.). +
        • +
        +

        Terminating instructions are a semantic requirement of the LLVM IR. There + is no facility for implicitly chaining together blocks placed into a function + in the order they occur. Indeed, in the general case, blocks will not be + added to the function in the order of execution because of the recursive + way compilers are written.

        +

        Furthermore, if you don't terminate your blocks, your compiler code will + compile just fine. You won't find out about the problem until you're running + the compiler and the module you just created fails on the LLVM Verifier.

        +
        + +
        Concrete Blocks
        +
        +

        After a little initial fumbling around, I quickly caught on to how blocks + should be constructed. In general, here's what I learned: +

          +
        1. Create your blocks early. While writing your compiler, you + will encounter several situations where you know apriori that you will + need several blocks. For example, if-then-else, switch, while, and for + statements in C/C++ all need multiple blocks for expression in LVVM. + The rule is, create them early.
        2. +
        3. Terminate your blocks early. This just reduces the chances + that you forget to terminate your blocks which is required (go + here for more). +
        4. Use getTerminator() for instruction insertion. I noticed early on + that many of the constructors for the Instruction classes take an optional + insert_before argument. At first, I thought this was a mistake + because clearly the normal mode of inserting instructions would be one at + a time after some other instruction, not before. However, + if you hold on to your terminating instruction (or use the handy dandy + getTerminator() method on a BasicBlock), it can + always be used as the insert_before argument to your instruction + constructors. This causes the instruction to automatically be inserted in + the RightPlace™ place, just before the terminating instruction. The + nice thing about this design is that you can pass blocks around and insert + new instructions into them without ever knowing what instructions came + before. This makes for some very clean compiler design.
        5. +
        +

        The foregoing is such an important principal, its worth making an idiom:

        +
        + BasicBlock* bb = new BasicBlock();
        + bb->getInstList().push_back( new Branch( ... ) );
        + new Instruction(..., bb->getTerminator() );
        + 
        +

        To make this clear, consider the typical if-then-else statement + (see StackerCompiler::handle_if() method). We can set this up + in a single function using LLVM in the following way:

        +
        + using namespace llvm;
        + BasicBlock*
        + MyCompiler::handle_if( BasicBlock* bb, SetCondInst* condition )
        + {
        +     // Create the blocks to contain code in the structure of if/then/else
        +     BasicBlock* then_bb = new BasicBlock(); 
        +     BasicBlock* else_bb = new BasicBlock();
        +     BasicBlock* exit_bb = new BasicBlock();
        + 
        +     // Insert the branch instruction for the "if"
        +     bb->getInstList().push_back( new BranchInst( then_bb, else_bb, condition ) );
        + 
        +     // Set up the terminating instructions
        +     then->getInstList().push_back( new BranchInst( exit_bb ) );
        +     else->getInstList().push_back( new BranchInst( exit_bb ) );
        + 
        +     // Fill in the then part .. details excised for brevity
        +     this->fill_in( then_bb );
        + 
        +     // Fill in the else part .. details excised for brevity
        +     this->fill_in( else_bb );
        + 
        +     // Return a block to the caller that can be filled in with the code
        +     // that follows the if/then/else construct.
        +     return exit_bb;
        + }
        + 
        +

        Presumably in the foregoing, the calls to the "fill_in" method would add + the instructions for the "then" and "else" parts. They would use the third part + of the idiom almost exclusively (inserting new instructions before the + terminator). Furthermore, they could even recurse back to handle_if + should they encounter another if/then/else statement, and it will just work.

        +

        Note how cleanly this all works out. In particular, the push_back methods on + the BasicBlock's instruction list. These are lists of type + Instruction (which is also of type Value). To create + the "if" branch we merely instantiate a BranchInst that takes as + arguments the blocks to branch to and the condition to branch on. The + BasicBlock objects act like branch labels! This new + BranchInst terminates the BasicBlock provided + as an argument. To give the caller a way to keep inserting after calling + handle_if, we create an exit_bb block which is + returned + to the caller. Note that the exit_bb block is used as the + terminator for both the then_bb and the else_bb + blocks. This guarantees that no matter what else handle_if + or fill_in does, they end up at the exit_bb block. +

        +
        + +
        push_back Is Your Friend
        +
        +

        + One of the first things I noticed is the frequent use of the "push_back" + method on the various lists. This is so common that it is worth mentioning. + The "push_back" inserts a value into an STL list, vector, array, etc. at the + end. The method might have also been named "insert_tail" or "append". + Although I've used STL quite frequently, my use of push_back wasn't very + high in other programs. In LLVM, you'll use it all the time. +

        +
        + +
        The Wily GetElementPtrInst
        +
        +

        + It took a little getting used to and several rounds of postings to the LLVM + mailing list to wrap my head around this instruction correctly. Even though I had + read the Language Reference and Programmer's Manual a couple times each, I still + missed a few very key points: +

        +
          +
        • GetElementPtrInst gives you back a Value for the last thing indexed.
        • +
        • All global variables in LLVM are pointers.
        • +
        • Pointers must also be dereferenced with the GetElementPtrInst + instruction.
        • +
        +

        This means that when you look up an element in the global variable (assuming + it's a struct or array), you must deference the pointer first! For many + things, this leads to the idiom: +

        +
        + std::vector<Value*> index_vector;
        + index_vector.push_back( ConstantSInt::get( Type::LongTy, 0 );
        + // ... push other indices ...
        + GetElementPtrInst* gep = new GetElementPtrInst( ptr, index_vector );
        + 
        +

        For example, suppose we have a global variable whose type is [24 x int]. The + variable itself represents a pointer to that array. To subscript the + array, we need two indices, not just one. The first index (0) dereferences the + pointer. The second index subscripts the array. If you're a "C" programmer, this + will run against your grain because you'll naturally think of the global array + variable and the address of its first element as the same. That tripped me up + for a while until I realized that they really do differ .. by type. + Remember that LLVM is strongly typed. Everything has a type. + The "type" of the global variable is [24 x int]*. That is, it's + a pointer to an array of 24 ints. When you dereference that global variable with + a single (0) index, you now have a "[24 x int]" type. Although + the pointer value of the dereferenced global and the address of the zero'th element + in the array will be the same, they differ in their type. The zero'th element has + type "int" while the pointer value has type "[24 x int]".

        +

        Get this one aspect of LLVM right in your head, and you'll save yourself + a lot of compiler writing headaches down the road.

        +
        + +
        Getting Linkage Types Right
        +
        +

        Linkage types in LLVM can be a little confusing, especially if your compiler + writing mind has affixed firm concepts to particular words like "weak", + "external", "global", "linkonce", etc. LLVM does not use the precise + definitions of, say, ELF or GCC, even though they share common terms. To be fair, + the concepts are related and similar but not precisely the same. This can lead + you to think you know what a linkage type represents but in fact it is slightly + different. I recommend you read the + Language Reference on this topic very + carefully. Then, read it again.

        +

        Here are some handy tips that I discovered along the way:

        +
          +
        • Uninitialized means external. That is, the symbol is declared in the current + module and can be used by that module, but it is not defined by that module.
        • +
        • Setting an initializer changes a global' linkage type. Setting an + initializer changes a global's linkage type from whatever it was to a normal, + defined global (not external). You'll need to call the setLinkage() method to + reset it if you specify the initializer after the GlobalValue has been constructed. + This is important for LinkOnce and Weak linkage types.
        • +
        • Appending linkage can keep track of things. Appending linkage can + be used to keep track of compilation information at runtime. It could be used, + for example, to build a full table of all the C++ virtual tables or hold the + C++ RTTI data, or whatever. Appending linkage can only be applied to arrays. + All arrays with the same name in each module are concatenated together at link + time.
        • +
        +
        + +
        Constants Are Easier Than That!
        +
        +

        + Constants in LLVM took a little getting used to until I discovered a few utility + functions in the LLVM IR that make things easier. Here's what I learned:

        +
          +
        • Constants are Values like anything else and can be operands of instructions
        • +
        • Integer constants, frequently needed, can be created using the static "get" + methods of the ConstantInt, ConstantSInt, and ConstantUInt classes. The nice thing + about these is that you can "get" any kind of integer quickly.
        • +
        • There's a special method on Constant class which allows you to get the null + constant for any type. This is really handy for initializing large + arrays or structures, etc.
        • +
        +
        + + +

        This section describes the Stacker language

        +
        The Stack
        +
        +

        Stacker definitions define what they do to the global stack. Before + proceeding, a few words about the stack are in order. The stack is simply + a global array of 32-bit integers or pointers. A global index keeps track + of the location of the top of the stack. All of this is hidden from the + programmer, but it needs to be noted because it is the foundation of the + conceptual programming model for Stacker. When you write a definition, + you are, essentially, saying how you want that definition to manipulate + the global stack.

        +

        Manipulating the stack can be quite hazardous. There is no distinction + given and no checking for the various types of values that can be placed + on the stack. Automatic coercion between types is performed. In many + cases, this is useful. For example, a boolean value placed on the stack + can be interpreted as an integer with good results. However, using a + word that interprets that boolean value as a pointer to a string to + print out will almost always yield a crash. Stacker simply leaves it + to the programmer to get it right without any interference or hindering + on interpretation of the stack values. You've been warned. :)

        +
        + +
        Punctuation
        +
        +

        Punctuation in Stacker is very simple. The colon and semi-colon + characters are used to introduce and terminate a definition + (respectively). Except for FORWARD declarations, definitions + are all you can specify in Stacker. Definitions are read left to right. + Immediately after the colon comes the name of the word being defined. + The remaining words in the definition specify what the word does. The definition + is terminated by a semi-colon.

        +

        So, your typical definition will have the form:

        +
        : name ... ;
        +

        The name is up to you but it must start with a letter and contain + only letters, numbers, and underscore. Names are case sensitive and must not be + the same as the name of a built-in word. The ... is replaced by + the stack manipulating words that you wish to define name as.

        +

        + +
        Comments
        +
        +

        Stacker supports two types of comments. A hash mark (#) starts a comment + that extends to the end of the line. It is identical to the kind of comments + commonly used in shell scripts. A pair of parentheses also surround a comment. + In both cases, the content of the comment is ignored by the Stacker compiler. The + following does nothing in Stacker. +

        +
        
        + # This is a comment to end of line
        + ( This is an enclosed comment )
        + 
        +

        See the example program to see comments in use in + a real program.

        +
        + +
        Literals
        +
        +

        There are three kinds of literal values in Stacker: Integers, Strings, + and Booleans. In each case, the stack operation is to simply push the + value on to the stack. So, for example:
        + 42 " is the answer." TRUE
        + will push three values on to the stack: the integer 42, the + string " is the answer.", and the boolean TRUE.

        +
        + +
        Words
        +
        +

        Each definition in Stacker is composed of a set of words. Words are + read and executed in order from left to right. There is very little + checking in Stacker to make sure you're doing the right thing with + the stack. It is assumed that the programmer knows how the stack + transformation he applies will affect the program.

        +

        Words in a definition come in two flavors: built-in and programmer + defined. Simply mentioning the name of a previously defined or declared + programmer-defined word causes that word's stack actions to be invoked. It + is somewhat like a function call in other languages. The built-in + words have various effects, described below.

        +

        Sometimes you need to call a word before it is defined. For this, you can + use the FORWARD declaration. It looks like this:

        +

        FORWARD name ;

        +

        This simply states to Stacker that "name" is the name of a definition + that is defined elsewhere. Generally it means the definition can be found + "forward" in the file. But, it doesn't have to be in the current compilation + unit. Anything declared with FORWARD is an external symbol for + linking.

        +
        + +
        Standard Style
        +
        +

        TODO

        +
        + +
        Built In Words
        +
        +

        The built-in words of the Stacker language are put in several groups + depending on what they do. The groups are as follows:

        +
          +
        1. Logical: These words provide the logical operations for + comparing stack operands.
          The words are: < > <= >= + = <> true false.
        2. +
        3. Bitwise: These words perform bitwise computations on + their operands.
          The words are: << >> XOR AND NOT
        4. +
        5. Arithmetic: These words perform arithmetic computations on + their operands.
          The words are: ABS NEG + - * / MOD */ ++ -- MIN MAX
        6. +
        7. StackThese words manipulate the stack directly by moving + its elements around.
          The words are: DROP DROP2 NIP NIP2 DUP DUP2 + SWAP SWAP2 OVER OVER2 ROT ROT2 RROT RROT2 TUCK TUCK2 PICK SELECT ROLL
        8. +
        9. MemoryThese words allocate, free, and manipulate memory + areas outside the stack.
          The words are: MALLOC FREE GET PUT
        10. +
        11. Control: These words alter the normal left to right flow + of execution.
          The words are: IF ELSE ENDIF WHILE END RETURN EXIT RECURSE
        12. +
        13. I/O: These words perform output on the standard output + and input on the standard input. No other I/O is possible in Stacker. +
          The words are: SPACE TAB CR >s >d >c <s <d <c.
        14. +
        +

        While you may be familiar with many of these operations from other + programming languages, a careful review of their semantics is important + for correct programming in Stacker. Of most importance is the effect + that each of these built-in words has on the global stack. The effect is + not always intuitive. To better describe the effects, we'll borrow from Forth the idiom of + describing the effect on the stack with:

        +

        BEFORE -- AFTER

        +

        That is, to the left of the -- is a representation of the stack before + the operation. To the right of the -- is a representation of the stack + after the operation. In the table below that describes the operation of + each of the built in words, we will denote the elements of the stack + using the following construction:

        +
          +
        1. b - a boolean truth value
        2. +
        3. w - a normal integer valued word.
        4. +
        5. s - a pointer to a string value
        6. +
        7. p - a pointer to a malloc'd memory block
        8. +
        +
        +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Definition Of Operation Of Built In Words
        LOGICAL OPERATIONS
        WordNameOperationDescription
        <LTw1 w2 -- bTwo values (w1 and w2) are popped off the stack and + compared. If w1 is less than w2, TRUE is pushed back on + the stack, otherwise FALSE is pushed back on the stack.
        >GTw1 w2 -- bTwo values (w1 and w2) are popped off the stack and + compared. If w1 is greater than w2, TRUE is pushed back on + the stack, otherwise FALSE is pushed back on the stack.
        >=GEw1 w2 -- bTwo values (w1 and w2) are popped off the stack and + compared. If w1 is greater than or equal to w2, TRUE is + pushed back on the stack, otherwise FALSE is pushed back + on the stack.
        <=LEw1 w2 -- bTwo values (w1 and w2) are popped off the stack and + compared. If w1 is less than or equal to w2, TRUE is + pushed back on the stack, otherwise FALSE is pushed back + on the stack.
        =EQw1 w2 -- bTwo values (w1 and w2) are popped off the stack and + compared. If w1 is equal to w2, TRUE is + pushed back on the stack, otherwise FALSE is pushed back +
        <>NEw1 w2 -- bTwo values (w1 and w2) are popped off the stack and + compared. If w1 is equal to w2, TRUE is + pushed back on the stack, otherwise FALSE is pushed back +
        FALSEFALSE -- bThe boolean value FALSE (0) is pushed on to the stack.
        TRUETRUE -- bThe boolean value TRUE (-1) is pushed on to the stack.
        BITWISE OPERATORS
        WordNameOperationDescription
        <<SHLw1 w2 -- w1<<w2Two values (w1 and w2) are popped off the stack. The w2 + operand is shifted left by the number of bits given by the + w1 operand. The result is pushed back to the stack.
        >>SHRw1 w2 -- w1>>w2Two values (w1 and w2) are popped off the stack. The w2 + operand is shifted right by the number of bits given by the + w1 operand. The result is pushed back to the stack.
        ORORw1 w2 -- w2|w1Two values (w1 and w2) are popped off the stack. The values + are bitwise OR'd together and pushed back on the stack. This is + not a logical OR. The sequence 1 2 OR yields 3 not 1.
        ANDANDw1 w2 -- w2&w1Two values (w1 and w2) are popped off the stack. The values + are bitwise AND'd together and pushed back on the stack. This is + not a logical AND. The sequence 1 2 AND yields 0 not 1.
        XORXORw1 w2 -- w2^w1Two values (w1 and w2) are popped off the stack. The values + are bitwise exclusive OR'd together and pushed back on the stack. + For example, The sequence 1 3 XOR yields 2.
        ARITHMETIC OPERATORS
        WordNameOperationDescription
        ABSABSw -- |w|One value s popped off the stack; its absolute value is computed + and then pushed on to the stack. If w1 is -1 then w2 is 1. If w1 is + 1 then w2 is also 1.
        NEGNEGw -- -wOne value is popped off the stack which is negated and then + pushed back on to the stack. If w1 is -1 then w2 is 1. If w1 is + 1 then w2 is -1.
        + ADDw1 w2 -- w2+w1Two values are popped off the stack. Their sum is pushed back + on to the stack
        - SUBw1 w2 -- w2-w1Two values are popped off the stack. Their difference is pushed back + on to the stack
        * MULw1 w2 -- w2*w1Two values are popped off the stack. Their product is pushed back + on to the stack
        / DIVw1 w2 -- w2/w1Two values are popped off the stack. Their quotient is pushed back + on to the stack
        MODMODw1 w2 -- w2%w1Two values are popped off the stack. Their remainder after division + of w1 by w2 is pushed back on to the stack
        */ STAR_SLAHw1 w2 w3 -- (w3*w2)/w1Three values are popped off the stack. The product of w1 and w2 is + divided by w3. The result is pushed back on to the stack.
        ++ INCRw -- w+1One value is popped off the stack. It is incremented by one and then + pushed back on to the stack.
        -- DECRw -- w-1One value is popped off the stack. It is decremented by one and then + pushed back on to the stack.
        MINMINw1 w2 -- (w2<w1?w2:w1)Two values are popped off the stack. The larger one is pushed back + on to the stack.
        MAXMAXw1 w2 -- (w2>w1?w2:w1)Two values are popped off the stack. The larger value is pushed back + on to the stack.
        STACK MANIPULATION OPERATORS
        WordNameOperationDescription
        DROPDROPw -- One value is popped off the stack.
        DROP2DROP2w1 w2 -- Two values are popped off the stack.
        NIPNIPw1 w2 -- w2The second value on the stack is removed from the stack. That is, + a value is popped off the stack and retained. Then a second value is + popped and the retained value is pushed.
        NIP2NIP2w1 w2 w3 w4 -- w3 w4The third and fourth values on the stack are removed from it. That is, + two values are popped and retained. Then two more values are popped and + the two retained values are pushed back on.
        DUPDUPw1 -- w1 w1One value is popped off the stack. That value is then pushed on to + the stack twice to duplicate the top stack vaue.
        DUP2DUP2w1 w2 -- w1 w2 w1 w2The top two values on the stack are duplicated. That is, two vaues + are popped off the stack. They are alternately pushed back on the + stack twice each.
        SWAPSWAPw1 w2 -- w2 w1The top two stack items are reversed in their order. That is, two + values are popped off the stack and pushed back on to the stack in + the opposite order they were popped.
        SWAP2SWAP2w1 w2 w3 w4 -- w3 w4 w2 w1The top four stack items are swapped in pairs. That is, two values + are popped and retained. Then, two more values are popped and retained. + The values are pushed back on to the stack in the reverse order but + in pairs.
        OVEROVERw1 w2-- w1 w2 w1Two values are popped from the stack. They are pushed back + on to the stack in the order w1 w2 w1. This seems to cause the + top stack element to be duplicated "over" the next value.
        OVER2OVER2w1 w2 w3 w4 -- w1 w2 w3 w4 w1 w2The third and fourth values on the stack are replicated on to the + top of the stack
        ROTROTw1 w2 w3 -- w2 w3 w1The top three values are rotated. That is, three value are popped + off the stack. They are pushed back on to the stack in the order + w1 w3 w2.
        ROT2ROT2w1 w2 w3 w4 w5 w6 -- w3 w4 w5 w6 w1 w2Like ROT but the rotation is done using three pairs instead of + three singles.
        RROTRROTw1 w2 w3 -- w2 w3 w1Reverse rotation. Like ROT, but it rotates the other way around. + Essentially, the third element on the stack is moved to the top + of the stack.
        RROT2RROT2w1 w2 w3 w4 w5 w6 -- w3 w4 w5 w6 w1 w2Double reverse rotation. Like RROT but the rotation is done using + three pairs instead of three singles. The fifth and sixth stack + elements are moved to the first and second positions
        TUCKTUCKw1 w2 -- w2 w1 w2Similar to OVER except that the second operand is being + replicated. Essentially, the first operand is being "tucked" + in between two instances of the second operand. Logically, two + values are popped off the stack. They are placed back on the + stack in the order w2 w1 w2.
        TUCK2TUCK2w1 w2 w3 w4 -- w3 w4 w1 w2 w3 w4Like TUCK but a pair of elements is tucked over two pairs. + That is, the top two elements of the stack are duplicated and + inserted into the stack at the fifth and positions.
        PICKPICKx0 ... Xn n -- x0 ... Xn x0The top of the stack is used as an index into the remainder of + the stack. The element at the nth position replaces the index + (top of stack). This is useful for cycling through a set of + values. Note that indexing is zero based. So, if n=0 then you + get the second item on the stack. If n=1 you get the third, etc. + Note also that the index is replaced by the n'th value.
        SELECTSELECTm n X0..Xm Xm+1 .. Xn -- XmThis is like PICK but the list is removed and you need to specify + both the index and the size of the list. Careful with this one, + the wrong value for n can blow away a huge amount of the stack.
        ROLLROLLx0 x1 .. xn n -- x1 .. xn x0Not Implemented. This one has been left as an exercise to + the student. See Exercise. ROLL requires + a value, "n", to be on the top of the stack. This value specifies how + far into the stack to "roll". The n'th value is moved (not + copied) from its location and replaces the "n" value on the top of the + stack. In this way, all the values between "n" and x0 roll up the stack. + The operation of ROLL is a generalized ROT. The "n" value specifies + how much to rotate. That is, ROLL with n=1 is the same as ROT and + ROLL with n=2 is the same as ROT2.
        MEMORY OPERATORS
        WordNameOperationDescription
        MALLOCMALLOCw1 -- pOne value is popped off the stack. The value is used as the size + of a memory block to allocate. The size is in bytes, not words. + The memory allocation is completed and the address of the memory + block is pushed on to the stack.
        FREEFREEp -- One pointer value is popped off the stack. The value should be + the address of a memory block created by the MALLOC operation. The + associated memory block is freed. Nothing is pushed back on the + stack. Many bugs can be created by attempting to FREE something + that isn't a pointer to a MALLOC allocated memory block. Make + sure you know what's on the stack. One way to do this is with + the following idiom:
        + 64 MALLOC DUP DUP (use ptr) DUP (use ptr) ... FREE +
        This ensures that an extra copy of the pointer is placed on + the stack (for the FREE at the end) and that every use of the + pointer is preceded by a DUP to retain the copy for FREE.
        GETGETw1 p -- w2 pAn integer index and a pointer to a memory block are popped of + the block. The index is used to index one byte from the memory + block. That byte value is retained, the pointer is pushed again + and the retained value is pushed. Note that the pointer value + s essentially retained in its position so this doesn't count + as a "use ptr" in the FREE idiom.
        PUTPUTw1 w2 p -- p An integer value is popped of the stack. This is the value to + be put into a memory block. Another integer value is popped of + the stack. This is the indexed byte in the memory block. A + pointer to the memory block is popped off the stack. The + first value (w1) is then converted to a byte and written + to the element of the memory block(p) at the index given + by the second value (w2). The pointer to the memory block is + pushed back on the stack so this doesn't count as a "use ptr" + in the FREE idiom.
        CONTROL FLOW OPERATORS
        WordNameOperationDescription
        RETURNRETURN -- The currently executing definition returns immediately to its caller. + Note that there is an implicit RETURN at the end of each + definition, logically located at the semi-colon. The sequence + RETURN ; is valid but redundant.
        EXITEXITw1 -- A return value for the program is popped off the stack. The program is + then immediately terminated. This is normally an abnormal exit from the + program. For a normal exit (when MAIN finishes), the exit + code will always be zero in accordance with UNIX conventions.
        RECURSERECURSE -- The currently executed definition is called again. This operation is + needed since the definition of a word doesn't exist until the semi colon + is reacher. Attempting something like:
        + : recurser recurser ;
        will yield and error saying that + "recurser" is not defined yet. To accomplish the same thing, change this + to:
        + : recurser RECURSE ;
        IF (words...) ENDIFIF (words...) ENDIFb -- A boolean value is popped of the stack. If it is non-zero then the "words..." + are executed. Otherwise, execution continues immediately following the ENDIF.
        IF (words...) ELSE (words...) ENDIFIF (words...) ELSE (words...) ENDIFb -- A boolean value is popped of the stack. If it is non-zero then the "words..." + between IF and ELSE are executed. Otherwise the words between ELSE and ENDIF are + executed. In either case, after the (words....) have executed, execution continues + immediately following the ENDIF.
        WHILE (words...) ENDWHILE (words...) ENDb -- b The boolean value on the top of the stack is examined. If it is non-zero then the + "words..." between WHILE and END are executed. Execution then begins again at the WHILE where another + boolean is popped off the stack. To prevent this operation from eating up the entire + stack, you should push on to the stack (just before the END) a boolean value that indicates + whether to terminate. Note that since booleans and integers can be coerced you can + use the following "for loop" idiom:
        + (push count) WHILE (words...) -- END
        + For example:
        + 10 WHILE DUP >d -- END
        + This will print the numbers from 10 down to 1. 10 is pushed on the stack. Since that is + non-zero, the while loop is entered. The top of the stack (10) is duplicated and then + printed out with >d. The top of the stack is decremented, yielding 9 and control is + transfered back to the WHILE keyword. The process starts all over again and repeats until + the top of stack is decremented to 0 at which the WHILE test fails and control is + transfered to the word after the END.
        INPUT & OUTPUT OPERATORS
        WordNameOperationDescription
        SPACESPACE -- A space character is put out. There is no stack effect.
        TABTAB -- A tab character is put out. There is no stack effect.
        CRCR -- A carriage return character is put out. There is no stack effect.
        >sOUT_STR -- A string pointer is popped from the stack. It is put out.
        >dOUT_STR -- A value is popped from the stack. It is put out as a decimal + integer.
        >cOUT_CHR -- A value is popped from the stack. It is put out as an ASCII + character.
        <sIN_STR -- s A string is read from the input via the scanf(3) format string " %as". + The resulting string is pushed on to the stack.
        <dIN_STR -- w An integer is read from the input via the scanf(3) format string " %d". + The resulting value is pushed on to the stack
        <cIN_CHR -- w A single character is read from the input via the scanf(3) format string + " %c". The value is converted to an integer and pushed on to the stack.
        DUMPDUMP -- The stack contents are dumped to standard output. This is useful for + debugging your definitions. Put DUMP at the beginning and end of a definition + to see instantly the net effect of the definition.
        + +
        + + +
        +

        The following fully documented program highlights many features of both + the Stacker language and what is possible with LLVM. The program has two modes + of operation. If you provide numeric arguments to the program, it checks to see + if those arguments are prime numbers and prints out the results. Without any + arguments, the program prints out any prime numbers it finds between 1 and one + million (there's a lot of them!). The source code comments below tell the + remainder of the story. +

        +
        +
        +
        
        + ################################################################################
        + #
        + # Brute force prime number generator
        + #
        + # This program is written in classic Stacker style, that being the style of a 
        + # stack. Start at the bottom and read your way up !
        + #
        + # Reid Spencer - Nov 2003 
        + ################################################################################
        + # Utility definitions
        + ################################################################################
        + : print >d CR ;
        + : it_is_a_prime TRUE ;
        + : it_is_not_a_prime FALSE ;
        + : continue_loop TRUE ;
        + : exit_loop FALSE;
        +     
        + ################################################################################
        + # This definition tries an actual division of a candidate prime number. It
        + # determines whether the division loop on this candidate should continue or
        + # not.
        + # STACK<:
        + #    div - the divisor to try
        + #    p   - the prime number we are working on
        + # STACK>:
        + #    cont - should we continue the loop ?
        + #    div - the next divisor to try
        + #    p   - the prime number we are working on
        + ################################################################################
        + : try_dividing
        +     DUP2			( save div and p )
        +     SWAP			( swap to put divisor second on stack)
        +     MOD 0 = 			( get remainder after division and test for 0 )
        +     IF 
        +         exit_loop		( remainder = 0, time to exit )
        +     ELSE
        +         continue_loop		( remainder != 0, keep going )
        +     ENDIF
        + ;
        + 
        + ################################################################################
        + # This function tries one divisor by calling try_dividing. But, before doing
        + # that it checks to see if the value is 1. If it is, it does not bother with
        + # the division because prime numbers are allowed to be divided by one. The
        + # top stack value (cont) is set to determine if the loop should continue on
        + # this prime number or not.
        + # STACK<:
        + #    cont - should we continue the loop (ignored)?
        + #    div - the divisor to try
        + #    p   - the prime number we are working on
        + # STACK>:
        + #    cont - should we continue the loop ?
        + #    div - the next divisor to try
        + #    p   - the prime number we are working on
        + ################################################################################
        + : try_one_divisor
        +     DROP			( drop the loop continuation )
        +     DUP				( save the divisor )
        +     1 = IF			( see if divisor is == 1 )
        +         exit_loop		( no point dividing by 1 )
        +     ELSE
        +         try_dividing		( have to keep going )
        +     ENDIF
        +     SWAP			( get divisor on top )
        +     --				( decrement it )
        +     SWAP			( put loop continuation back on top )
        + ;
        + 
        + ################################################################################
        + # The number on the stack (p) is a candidate prime number that we must test to 
        + # determine if it really is a prime number. To do this, we divide it by every 
        + # number from one p-1 to 1. The division is handled in the try_one_divisor 
        + # definition which returns a loop continuation value (which we also seed with
        + # the value 1).  After the loop, we check the divisor. If it decremented all
        + # the way to zero then we found a prime, otherwise we did not find one.
        + # STACK<:
        + #   p - the prime number to check
        + # STACK>:
        + #   yn - boolean indicating if its a prime or not
        + #   p - the prime number checked
        + ################################################################################
        + : try_harder
        +     DUP 			( duplicate to get divisor value ) )
        +     --				( first divisor is one less than p )
        +     1				( continue the loop )
        +     WHILE
        +        try_one_divisor		( see if its prime )
        +     END
        +     DROP			( drop the continuation value )
        +     0 = IF			( test for divisor == 1 )
        +        it_is_a_prime		( we found one )
        +     ELSE
        +        it_is_not_a_prime	( nope, this one is not a prime )
        +     ENDIF
        + ;
        + 
        + ################################################################################
        + # This definition determines if the number on the top of the stack is a prime 
        + # or not. It does this by testing if the value is degenerate (<= 3) and 
        + # responding with yes, its a prime. Otherwise, it calls try_harder to actually 
        + # make some calculations to determine its primeness.
        + # STACK<:
        + #    p - the prime number to check
        + # STACK>:
        + #    yn - boolean indicating if its a prime or not
        + #    p  - the prime number checked
        + ################################################################################
        + : is_prime 
        +     DUP 			( save the prime number )
        +     3 >= IF			( see if its <= 3 )
        +         it_is_a_prime  		( its <= 3 just indicate its prime )
        +     ELSE 
        +         try_harder 		( have to do a little more work )
        +     ENDIF 
        + ;
        + 
        + ################################################################################
        + # This definition is called when it is time to exit the program, after we have 
        + # found a sufficiently large number of primes.
        + # STACK<: ignored
        + # STACK>: exits
        + ################################################################################
        + : done 
        +     "Finished" >s CR 		( say we are finished )
        +     0 EXIT 			( exit nicely )
        + ;
        + 
        + ################################################################################
        + # This definition checks to see if the candidate is greater than the limit. If 
        + # it is, it terminates the program by calling done. Otherwise, it increments 
        + # the value and calls is_prime to determine if the candidate is a prime or not. 
        + # If it is a prime, it prints it. Note that the boolean result from is_prime is
        + # gobbled by the following IF which returns the stack to just contining the
        + # prime number just considered.
        + # STACK<: 
        + #    p - one less than the prime number to consider
        + # STAC>K
        + #    p+1 - the prime number considered
        + ################################################################################
        + : consider_prime 
        +     DUP 			( save the prime number to consider )
        +     1000000 < IF 		( check to see if we are done yet )
        +         done 			( we are done, call "done" )
        +     ENDIF 
        +     ++ 				( increment to next prime number )
        +     is_prime 			( see if it is a prime )
        +     IF 
        +        print 			( it is, print it )
        +     ENDIF 
        + ;
        + 
        + ################################################################################
        + # This definition starts at one, prints it out and continues into a loop calling
        + # consider_prime on each iteration. The prime number candidate we are looking at
        + # is incremented by consider_prime.
        + # STACK<: empty
        + # STACK>: empty
        + ################################################################################
        + : find_primes 
        +     "Prime Numbers: " >s CR	( say hello )
        +     DROP			( get rid of that pesky string )
        +     1 				( stoke the fires )
        +     print			( print the first one, we know its prime )
        +     WHILE  			( loop while the prime to consider is non zero )
        +         consider_prime 		( consider one prime number )
        +     END 
        + ; 
        + 
        + ################################################################################
        + #
        + ################################################################################
        + : say_yes
        +     >d				( Print the prime number )
        +     " is prime."		( push string to output )
        +     >s				( output it )
        +     CR				( print carriage return )
        +     DROP			( pop string )
        + ;
        + 
        + : say_no
        +     >d				( Print the prime number )
        +     " is NOT prime."		( push string to put out )
        +     >s				( put out the string )
        +     CR				( print carriage return )
        +     DROP			( pop string )
        + ;
        + 
        + ################################################################################
        + # This definition processes a single command line argument and determines if it
        + # is a prime number or not.
        + # STACK<:
        + #    n - number of arguments
        + #    arg1 - the prime numbers to examine
        + # STACK>:
        + #    n-1 - one less than number of arguments
        + #    arg2 - we processed one argument
        + ################################################################################
        + : do_one_argument
        +     --				( decrement loop counter )
        +     SWAP			( get the argument value  )
        +     is_prime IF			( determine if its prime )
        +         say_yes			( uhuh )
        +     ELSE
        +         say_no			( nope )
        +     ENDIF
        +     DROP			( done with that argument )
        + ;
        + 
        + ################################################################################
        + # The MAIN program just prints a banner and processes its arguments.
        + # STACK<:
        + #    n - number of arguments
        + #    ... - the arguments
        + ################################################################################
        + : process_arguments
        +     WHILE			( while there are more arguments )
        +        do_one_argument		( process one argument )
        +     END
        + ;
        +     
        + ################################################################################
        + # The MAIN program just prints a banner and processes its arguments.
        + # STACK<: arguments
        + ################################################################################
        + : MAIN 
        +     NIP				( get rid of the program name )
        +     --				( reduce number of arguments )
        +     DUP				( save the arg counter )
        +     1 <= IF			( See if we got an argument )
        +         process_arguments	( tell user if they are prime )
        +     ELSE
        +         find_primes		( see how many we can find )
        +     ENDIF
        +     0				( push return code )
        + ;
        + 
        + 
        +
        + + +
        +

        This section is under construction. +

        In the mean time, you can always read the code! It has comments!

        +
        + + +
        +

        The source code, test programs, and sample programs can all be found + under the LLVM "projects" directory. You will need to obtain the LLVM sources + to find it (either via anonymous CVS or a tarball. See the + Getting Started document).

        +

        Under the "projects" directory there is a directory named "Stacker". That + directory contains everything, as follows:

        +
          +
        • lib - contains most of the source code +
            +
          • lib/compiler - contains the compiler library +
          • lib/runtime - contains the runtime library +
        • +
        • test - contains the test programs
        • +
        • tools - contains the Stacker compiler main program, stkrc +
            +
          • lib/stkrc - contains the Stacker compiler main program + +
          • sample - contains the sample programs
          • +
          +
        + +
        The Lexer
        +
        +

        See projects/Stacker/lib/compiler/Lexer.l

        +
        + +
        The Parser
        +
        +

        See projects/Stacker/lib/compiler/StackerParser.y

        +
        + +
        The Compiler
        +
        +

        See projects/Stacker/lib/compiler/StackerCompiler.cpp

        +
        + +
        The Runtime
        +
        +

        See projects/Stacker/lib/runtime/stacker_rt.c

        +
        + +
        Compiler Driver
        +
        +

        See projects/Stacker/tools/stkrc/stkrc.cpp

        +
        + +
        Test Programs
        +
        +

        See projects/Stacker/test/*.st

        +
        + + +
        +

        As you may have noted from a careful inspection of the Built-In word + definitions, the ROLL word is not implemented. This word was left out of + Stacker on purpose so that it can be an exercise for the student. The exercise + is to implement the ROLL functionality (in your own workspace) and build a test + program for it. If you can implement ROLL, you understand Stacker and probably + a fair amount about LLVM since this is one of the more complicated Stacker + operations. The work will almost be completely limited to the + compiler. +

        The ROLL word is already recognized by both the lexer and parser but ignored + by the compiler. That means you don't have to futz around with figuring out how + to get the keyword recognized. It already is. The part of the compiler that + you need to implement is the ROLL case in the + StackerCompiler::handle_word(int) method.

        See the + implementations of PICK and SELECT in the same method to get some hints about + how to complete this exercise.

        +

        Good luck!

        +
        + + +
        +

        The initial implementation of Stacker has several deficiencies. If you're + interested, here are some things that could be implemented better:

        +
          +
        1. Write an LLVM pass to compute the correct stack depth needed by the + program. Currently the stack is set to a fixed number which means programs + with large numbers of definitions might fail.
        2. +
        3. Write an LLVM pass to optimize the use of the global stack. The code + emitted currently is somewhat wasteful. It gets cleaned up a lot by existing + passes but more could be done.
        4. +
        5. Add -O -O1 -O2 and -O3 optimization switches to the compiler driver to + allow LLVM optimization without using "opt."
        6. +
        7. Make the compiler driver use the LLVM linking facilities (with IPO) + before depending on GCC to do the final link.
        8. +
        9. Clean up parsing. It doesn't handle errors very well.
        10. +
        11. Rearrange the StackerCompiler.cpp code to make better use of inserting + instructions before a block's terminating instruction. I didn't figure this + technique out until I was nearly done with LLVM. As it is, its a bad example + of how to insert instructions!
        12. +
        13. Provide for I/O to arbitrary files instead of just stdin/stdout.
        14. +
        15. Write additional built-in words; with inspiration from FORTH
        16. +
        17. Write additional sample Stacker programs.
        18. +
        19. Add your own compiler writing experiences and tips in the + Lessons I Learned About LLVM section.
        20. +
        +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Reid Spencer
        + LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:04 $ +
        + + + Index: llvm-www/releases/1.3/docs/SystemLibrary.html diff -c /dev/null llvm-www/releases/1.3/docs/SystemLibrary.html:1.1 *** /dev/null Fri Aug 13 17:03:14 2004 --- llvm-www/releases/1.3/docs/SystemLibrary.html Fri Aug 13 17:03:04 2004 *************** *** 0 **** --- 1,203 ---- + + + + System Library + + + + +
        System Library
        + +
        +

        Warning: This document is a work in progress.

        +
        + + + +
        +

        Written by Reid Spencer

        +
        + + + + +
        +

        This document describes the requirements, design, and implementation + details of LLVM's System Library. The library is composed of the header files + in llvm/include/llvm/System and the source files in + llvm/lib/System. The goal of this library is to completely shield + LLVM from the variations in operating system interfaces. By centralizing + LLVM's use of operating system interfaces, we make it possible for the LLVM + tool chain and runtime libraries to be more easily ported to new platforms. + The library also unclutters the rest of LLVM from #ifdef use and special + cases for specific operating systems.

        +

        The System Library was donated to LLVM by Reid Spencer who formulated the + original design as part of the eXtensible Programming System (XPS) which is + based, in part, on LLVM.

        +
        + + + +
        +

        The System library's requirements are aimed at shielding LLVM from the + variations in operating system interfaces. The following sections define the + requirements needed to fulfill this objective.

        +
        + + + +
        +

        To be written.

        +
        + + + +
        +

        To be written.

        +
        + + + +
        +

        To be written.

        +
        + + + +
        +

        To be written.

        +
        + + + +
        +

        To be written.

        +
        + + + +
        +

        To be written.

        +
        + + + +
        +

        In order to fulfill the requirements of the system library, strict design + objectives must be maintained in the library as it evolves. The goal here + is to provide interfaces to operating system concepts (files, memory maps, + sockets, signals, locking, etc) efficiently and in such a way that the + remainder of LLVM is completely operating system agnostic.

        +
        + + + +
        +

        no public data

        +

        onlyprimitive typed private/protected data

        +

        data size is "right" for platform, not max of all platforms

        +

        each class corresponds to O/S concept

        +
        + + + +
        +

        To be written.

        +
        + + + +
        +

        To be written.

        +
        + + + +
        +

        To be written.

        +
        + + + +
        +

        To be written.

        +
        + + + +
        +

        To be written.

        +
        + + + +
        +

        To be written.

        +
        + + + +
        +

        See bug 351 + for further details on the progress of this work

        +
        + + + +
        +

        The linux implementation of the system library will always be the + reference implementation. This means that (a) the concepts defined by the + linux must be identically replicated in the other implementations and (b) the + linux implementation must always be complete (provide implementations for all + concepts).

        +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Reid Spencer
        + LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:04 $ +
        + + Index: llvm-www/releases/1.3/docs/TableGenFundamentals.html diff -c /dev/null llvm-www/releases/1.3/docs/TableGenFundamentals.html:1.1 *** /dev/null Fri Aug 13 17:03:15 2004 --- llvm-www/releases/1.3/docs/TableGenFundamentals.html Fri Aug 13 17:03:04 2004 *************** *** 0 **** --- 1,565 ---- + + + + TableGen Fundamentals + + + + +
        TableGen Fundamentals
        + + + +
        +

        Written by Chris Lattner

        +
        + + + + + +
        + +

        TableGen's purpose is to help a human develop and maintain records of + domain-specific information. Because there may be a large number of these + records, it is specifically designed to allow writing flexible descriptions and + for common features of these records to be factored out. This reduces the + amount of duplication in the description, reduces the chance of error, and + makes it easier to structure domain specific information.

        + +

        The core part of TableGen parses a file, instantiates + the declarations, and hands the result off to a domain-specific "TableGen backend" for processing. The current major user + of TableGen is the LLVM code generator.

        + +

        Note that if you work on TableGen much, and use emacs or vim, that you can + find an emacs "TableGen mode" and a vim language file in + llvm/utils/emacs and llvm/utils/vim directory of your LLVM + distribution, respectively.

        + +
        + + + + +
        + +

        TableGen files consist of two key parts: 'classes' and 'definitions', both + of which are considered 'records'.

        + +

        TableGen records have a unique name, a list of values, and a list of + superclasses. The list of values is main data that TableGen builds for each + record, it is this that holds the domain specific information for the + application. The interpretation of this data is left to a specific TableGen backend, but the structure and format rules are + taken care of and fixed by TableGen.

        + +

        TableGen definitions are the concrete form of 'records'. These + generally do not have any undefined values, and are marked with the + 'def' keyword.

        + +

        TableGen classes are abstract records that are used to build and + describe other records. These 'classes' allow the end-user to build + abstractions for either the domain they are targetting (such as "Register", + "RegisterClass", and "Instruction" in the LLVM code generator) or for the + implementor to help factor out common properties of records (such as "FPInst", + which is used to represent floating point instructions in the X86 backend). + TableGen keeps track of all of the classes that are used to build up a + definition, so the backend can find all definitions of a particular class, such + as "Instruction".

        + +
        + + + + +
        + +

        With no other arguments, TableGen parses the specified file and prints out + all of the classes, then all of the definitions. This is a good way to see what + the various definitions expand to fully. Running this on the X86.td + file prints this (at the time of this writing):

        + +
        + ...
        + def ADDrr8 {    // Instruction X86Inst I2A8 Pattern
        +   string Name = "add";
        +   string Namespace = "X86";
        +   list<Register> Uses = [];
        +   list<Register> Defs = [];
        +   bit isReturn = 0;
        +   bit isBranch = 0;
        +   bit isCall = 0;
        +   bit isTwoAddress = 1;
        +   bit isTerminator = 0;
        +   dag Pattern = (set R8, (plus R8, R8));
        +   bits<8> Opcode = { 0, 0, 0, 0, 0, 0, 0, 0 };
        +   Format Form = MRMDestReg;
        +   bits<5> FormBits = { 0, 0, 0, 1, 1 };
        +   ArgType Type = Arg8;
        +   bits<3> TypeBits = { 0, 0, 1 };
        +   bit hasOpSizePrefix = 0;
        +   bit printImplicitUses = 0;
        +   bits<4> Prefix = { 0, 0, 0, 0 };
        +   FPFormat FPForm = ?;
        +   bits<3> FPFormBits = { 0, 0, 0 };
        + }
        + ...
        + 
        + +

        This definition corresponds to an 8-bit register-register add instruction in + the X86. The string after the 'def' string indicates the name of the + record ("ADDrr8" in this case), and the comment at the end of the line + indicates the superclasses of the definition. The body of the record contains + all of the data that TableGen assembled for the record, indicating that the + instruction is part of the "X86" namespace, should be printed as "add" + in the assembly file, it is a two-address instruction, has a particular + encoding, etc. The contents and semantics of the information in the record is + specific to the needs of the X86 backend, and is only shown as an example.

        + +

        As you can see, a lot of information is needed for every instruction + supported by the code generator, and specifying it all manually would be + unmaintainble, prone to bugs, and tiring to do in the first place. Because we + are using TableGen, all of the information was derived from the following + definition:

        + +
        + def ADDrr8   : I2A8<"add", 0x00, MRMDestReg>,
        +                Pattern<(set R8, (plus R8, R8))>;
        + 
        + +

        This definition makes use of the custom I2A8 (two address instruction with + 8-bit operand) class, which is defined in the X86-specific TableGen file to + factor out the common features that instructions of its class share. A key + feature of TableGen is that it allows the end-user to define the abstractions + they prefer to use when describing their information.

        + +
        + + + + +
        + +

        TableGen runs just like any other LLVM tool. The first (optional) argument + specifies the file to read. If a filename is not specified, tblgen + reads from standard input.

        + +

        To be useful, one of the TableGen backends must be + used. These backends are selectable on the command line (type 'tblgen + --help' for a list). For example, to get a list of all of the definitions + that subclass a particular type (which can be useful for building up an enum + list of these records), use the --print-enums option:

        + +
        + $ tblgen X86.td -print-enums -class=Register
        + AH, AL, AX, BH, BL, BP, BX, CH, CL, CX, DH, DI, DL, DX,
        + EAX, EBP, EBX, ECX, EDI, EDX, ESI, ESP, FP0, FP1, FP2, FP3, FP4, FP5, FP6,
        + SI, SP, ST0, ST1, ST2, ST3, ST4, ST5, ST6, ST7, 
        + 
        + $ tblgen X86.td -print-enums -class=Instruction 
        + ADCrr32, ADDri16, ADDri16b, ADDri32, ADDri32b, ADDri8, ADDrr16, ADDrr32,
        + ADDrr8, ADJCALLSTACKDOWN, ADJCALLSTACKUP, ANDri16, ANDri16b, ANDri32, ANDri32b,
        + ANDri8, ANDrr16, ANDrr32, ANDrr8, BSWAPr32, CALLm32, CALLpcrel32, ...
        + 
        + +

        The default backend prints out all of the records, as described above.

        + +

        If you plan to use TableGen for some purpose, you will most likely have to + write a backend that extracts the information specific + to what you need and formats it in the appropriate way.

        + +
        + + + + + + +
        +

        TableGen doesn't care about the meaning of data (that is up to the backend + to define), but it does care about syntax, and it enforces a simple type system. + This section describes the syntax and the constructs allowed in a TableGen file. +

        +
        + + + + + + + +
        +

        TableGen supports BCPL style "//" comments, which run to the end of + the line, and it also supports nestable "/* */" comments.

        +
        + + + + +
        +

        TableGen files are strongly typed, in a simple (but complete) type-system. + These types are used to perform automatic conversions, check for errors, and to + help interface designers constrain the input that they allow. Every value definition is required to have an associated type. +

        + +

        TableGen supports a mixture of very low-level types (such as bit) + and very high-level types (such as dag). This flexibility is what + allows it to describe a wide range of information conveniently and compactly. + The TableGen types are:

        + +
          +
        • "bit" - A 'bit' is a boolean value that can hold either 0 or + 1.
        • + +
        • "int" - The 'int' type represents a simple 32-bit integer + value, such as 5.
        • + +
        • "string" - The 'string' type represents an ordered sequence + of characters of arbitrary length.
        • + +
        • "bits<n>" - A 'bits' type is an arbitrary, but fixed, + size integer that is broken up into individual bits. This type is useful + because it can handle some bits being defined while others are undefined.
        • + +
        • "list<ty>" - This type represents a list whose + elements are some other type. The contained type is arbitrary: it can even be + another list type.
        • + +
        • Class type - Specifying a class name in a type context means that the + defined value must be a subclass of the specified class. This is useful in + conjunction with the "list" type, for example, to constrain the elements of the + list to a common base class (e.g., a list<Register> can + only contain definitions derived from the "Register" class).
        • + +
        • "code" - This represents a big hunk of text. NOTE: I don't + remember why this is distinct from string!
        • + +
        • "dag" - This type represents a nestable directed graph of + elements.
        • +
        + +

        To date, these types have been sufficient for describing things that + TableGen has been used for, but it is straight-forward to extend this list if + needed.

        + +
        + + + + +
        + +

        TableGen allows for a pretty reasonable number of different expression forms + when building up values. These forms allow the TableGen file to be written in a + natural syntax and flavor for the application. The current expression forms + supported include:

        + +
          +
        • ? - uninitialized field
        • +
        • 0b1001011 - binary integer value
        • +
        • 07654321 - octal integer value (indicated by a leading 0)
        • +
        • 7 - decimal integer value
        • +
        • 0x7F - hexadecimal integer value
        • +
        • "foo" - string value
        • +
        • [{ ... }] - code fragment
        • +
        • [ X, Y, Z ] - list value.
        • +
        • { a, b, c } - initializer for a "bits<3>" value
        • +
        • value - value reference
        • +
        • value{17} - access to one bit of a value
        • +
        • value{15-17} - access to multiple bits of a value
        • +
        • DEF - reference to a record definition
        • +
        • X.Y - reference to the subfield of a value
        • +
        • list[4-7,17,2-3] - A slice of the 'list' list, including elements + 4,5,6,7,17,2, and 3 from it. Elements may be included multiple times.
        • +
        • (DEF a, b) - a dag value. The first element is required to be a + record definition, the remaining elements in the list may be arbitrary other + values, including nested `dag' values.
        • +
        + +

        Note that all of the values have rules specifying how they convert to values + for different types. These rules allow you to assign a value like "7" to a + "bits<4>" value, for example.

        + +
        + + + + +
        + +

        As mentioned in the intro, classes and definitions + (collectively known as 'records') in TableGen are the main high-level unit of + information that TableGen collects. Records are defined with a def or + class keyword, the record name, and an optional list of "template arguments". If the record has superclasses, + they are specified as a comma seperated list that starts with a colon character + (":"). If value definitions or let + expressions are needed for the class, they are enclosed in curly braces + ("{}"); otherwise, the record ends with a semicolon. Here is a simple TableGen + file:

        + +
        + class C { bit V = 1; }
        + def X : C;
        + def Y : C {
        +   string Greeting = "hello";
        + }
        + 
        + +

        This example defines two definitions, X and Y, both of + which derive from the C class. Because of this, they both get the + V bit value. The Y definition also gets the Greeting member + as well.

        + +

        In general, classes are useful for collecting together the commonality + between a group of records and isolating it in a single place. Also, classes + permit the specification of default values for their subclasses, allowing the + subclasses to override them as they wish.

        + +
        + + + + +
        +

        Value definitions define named entries in records. A value must be defined + before it can be referred to as the operand for another value definition or + before the value is reset with a let expression. A + value is defined by specifying a TableGen type and a name. + If an initial value is available, it may be specified after the type with an + equal sign. Value definitions require terminating semicolons.

        +
        + + + + +
        +

        A record-level let expression is used to change the value of a value + definition in a record. This is primarily useful when a superclass defines a + value that a derived class or definition wants to override. Let expressions + consist of the 'let' keyword followed by a value name, an equal sign + ("="), and a new value. For example, a new class could be added to the example + above, redefining the V field for all of its subclasses:

        + +
        + class D : C { let V = 0; }
        + def Z : D;
        + 
        + +

        In this case, the Z definition will have a zero value for its "V" + value, despite the fact that it derives (indirectly) from the C class, + because the D class overrode its value.

        + +
        + + + + +
        +

        TableGen permits the definition of parameterized classes as well as normal + concrete classes. Parameterized TableGen classes specify a list of variable + bindings (which may optionally have defaults) that are bound when used. Here is + a simple example:

        + +
        + class FPFormat<bits<3> val> {
        +   bits<3> Value = val;
        + }
        + def NotFP      : FPFormat<0>;
        + def ZeroArgFP  : FPFormat<1>;
        + def OneArgFP   : FPFormat<2>;
        + def OneArgFPRW : FPFormat<3>;
        + def TwoArgFP   : FPFormat<4>;
        + def SpecialFP  : FPFormat<5>;
        + 
        + +

        In this case, template arguments are used as a space efficient way to specify + a list of "enumeration values", each with a "Value" field set to the specified + integer.

        + +

        The more esoteric forms of TableGen expressions are + useful in conjunction with template arguments. As an example:

        + +
        + class ModRefVal<bits<2> val> {
        +   bits<2> Value = val;
        + }
        + 
        + def None   : ModRefVal<0>;
        + def Mod    : ModRefVal<1>;
        + def Ref    : ModRefVal<2>;
        + def ModRef : ModRefVal<3>;
        + 
        + class Value<ModRefVal MR> {
        +   // decode some information into a more convenient format, while providing
        +   // a nice interface to the user of the "Value" class.
        +   bit isMod = MR.Value{0};
        +   bit isRef = MR.Value{1};
        + 
        +   // other stuff...
        + }
        + 
        + // Example uses
        + def bork : Value<Mod>;
        + def zork : Value<Ref>;
        + def hork : Value<ModRef>;
        + 
        + +

        This is obviously a contrived example, but it shows how template arguments + can be used to decouple the interface provided to the user of the class from the + actual internal data representation expected by the class. In this case, + running tblgen on the example prints the following definitions:

        + +
        + def bork {      // Value
        +   bit isMod = 1;
        +   bit isRef = 0;
        + }
        + def hork {      // Value
        +   bit isMod = 1;
        +   bit isRef = 1;
        + }
        + def zork {      // Value
        +   bit isMod = 0;
        +   bit isRef = 1;
        + }
        + 
        + +

        This shows that TableGen was able to dig into the argument and extract a + piece of information that was requested by the designer of the "Value" class. + For more realistic examples, please see existing users of TableGen, such as the + X86 backend.

        + +
        + + + + + + + +
        +

        TableGen supports the 'include' token, which textually substitutes + the specified file in place of the include directive. The filename should be + specified as a double quoted string immediately after the 'include' + keyword. Example:

        + +
        + include "foo.td"
        + 
        + +
        + + + + +
        +

        "let" expressions at file scope are similar to "let" + expressions within a record, except they can specify a value binding for + multiple records at a time, and may be useful in certain other cases. + File-scope let expressions are really just another way that TableGen allows the + end-user to factor out commonality from the records.

        + +

        File-scope "let" expressions take a comma-seperated list of bindings to + apply, and one of more records to bind the values in. Here are some + examples:

        + +
        + let isTerminator = 1, isReturn = 1 in
        +   def RET : X86Inst<"ret", 0xC3, RawFrm, NoArg>;
        + 
        + 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>;
        +   }
        + 
        + +

        File-scope "let" expressions are often useful when a couple of definitions + need to be added to several records, and the records do not otherwise need to be + opened, as in the case with the CALL* instructions above.

        +
        + + + + + +
        +

        How they work, how to write one. This section should not contain details + about any particular backend, except maybe -print-enums as an example. This + should highlight the APIs in TableGen/Record.h.

        +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
        + LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:04 $ +
        + + + Index: llvm-www/releases/1.3/docs/TestingGuide.html diff -c /dev/null llvm-www/releases/1.3/docs/TestingGuide.html:1.1 *** /dev/null Fri Aug 13 17:03:15 2004 --- llvm-www/releases/1.3/docs/TestingGuide.html Fri Aug 13 17:03:04 2004 *************** *** 0 **** --- 1,420 ---- + + + + LLVM Test Suite Guide + + + + +
        + LLVM Test Suite Guide +
        + +
          +
        1. Overview
        2. +
        3. Requirements
        4. +
        5. Quick Start
        6. +
        7. LLVM Test Suite Organization +
        8. +
        9. LLVM Test Suite Tree
        10. +
        11. QMTest Structure
        12. +
        13. Programs Structure
        14. +
        15. Running the LLVM Tests
        16. +
        17. Running the nightly tester
        18. +
        + +
        +

        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. Note: + you will need QMTest + 2.0.3 (source tar.gz file) to be successful. The tests do not run with + any other version.
        + +
        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.

          • + +
        • + +
        • 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.

        + +
        + + + + + +
        + +

        + The LLVM Nightly Testers + automatically check out an LLVM tree, build it, run the "nightly" + program test (described above) and all of the regression tests, then + delete the checked out tree. This tester is designed to ensure that + programs don't break as well as keep track of LLVM's progress over time.

        + +

        + If you'd like to set up an instance of the nightly tester to run on your + machine, take a look at the comments at the top of the utils/NightlyTester.pl + file. We usually run it from a crontab entry that looks ilke this: +

        + +
        + 5 3 * * *       LLVM_LIB_SEARCH_PATH=.../llvm-gcc/bytecode-libs $HOME/llvm/utils/NightlyTest.pl -parallel -enable-linscan ...CVSREPOSTRING... $HOME/buildtest-X86 $HOME/cvs/testresults-X86
        + 
        + +

        + Take a look at the NightlyTest.pl file to see what all of the flags and + strings do. If you start running the nightly tests, please let us know and + we'll link your page to the global tester page. Thanks! +

        + +
        + + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + John T. Criswell
        + The LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:04 $ +
        + + Index: llvm-www/releases/1.3/docs/WritingAnLLVMPass.html diff -c /dev/null llvm-www/releases/1.3/docs/WritingAnLLVMPass.html:1.1 *** /dev/null Fri Aug 13 17:03:15 2004 --- llvm-www/releases/1.3/docs/WritingAnLLVMPass.html Fri Aug 13 17:03:04 2004 *************** *** 0 **** --- 1,1488 ---- + + + + Writing an LLVM Pass + + + + +
        + Writing an LLVM Pass +
        + +
          +
        1. Introduction - What is a pass?
        2. +
        3. Quick Start - Writing hello world +
        4. +
        5. Pass classes and requirements + +
        6. Pass Registration +
        7. +
        8. Specifying interactions between passes +
        9. +
        10. Implementing Analysis Groups +
        11. +
        12. What PassManager does +
        13. +
        14. Using GDB with dynamically loaded passes +
        15. +
        16. Future extensions planned +
        17. +
        + +
        +

        Written by Chris Lattner

        +
        + + + + + +
        + +

        The LLVM Pass Framework is an important part of the LLVM system, because LLVM + passes are where the interesting parts of the compiler exist. Passes perform + the transformations and optimizations that make up the compiler, they build + the analysis results that are used by these transformations, and they are, above + all, a structuring technique for compiler code.

        + +

        All LLVM passes are subclasses of the Pass + class, which implement functionality by overriding virtual methods inherited + from Pass. Depending on how your pass works, you may be able to + inherit from the FunctionPass + or BasicBlockPass, + which gives the system more information about what your pass does, and how it + can be combined with other passes. One of the main features of the LLVM Pass + Framework is that it schedules passes to run in an efficient way based on the + constraints that your pass has.

        + +

        We start by showing you how to construct a pass, everything from setting up + the code, to compiling, loading, and executing it. After the basics are down, + more advanced features are discussed.

        + +
        + + + + + +
        + +

        Here we describe how to write the "hello world" of passes. The "Hello" pass + is designed to simply print out the name of non-external functions that exist in + the program being compiled. It does not modify the program at all, just + inspects it. The source code and files for this pass are available in the LLVM + source tree in the lib/Transforms/Hello directory.

        + +
        + + + + +
        + +

        First thing you need to do is create a new directory somewhere in the LLVM + source base. For this example, we'll assume that you made + "lib/Transforms/Hello". The first thing you must do is set up a build + script (Makefile) that will compile the source code for the new pass. To do + this, copy this into "Makefile":

        + +
        + +
        + # Makefile for hello pass
        + 
        + # Path to top level of LLVM heirarchy
        + LEVEL = ../../..
        + 
        + # Name of the library to build
        + LIBRARYNAME = hello
        + 
        + # Build a dynamically loadable shared object
        + SHARED_LIBRARY = 1
        + 
        + # Include the makefile implementation stuff
        + include $(LEVEL)/Makefile.common
        + 
        + +

        This makefile specifies that all of the .cpp files in the current + directory are to be compiled and linked together into a + lib/Debug/libhello.so shared object that can be dynamically loaded by + the opt or analyze tools. If your operating system uses a + suffix other than .so (such as windows of Mac OS/X), the appropriate extension + will be used.

        + +

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

        + +
        + + + + +
        + +

        Now that we have a way to compile our new pass, we just have to write it. + Start out with:

        + +
        + #include "llvm/Pass.h"
        + #include "llvm/Function.h"
        + 
        + +

        Which are needed because we are writing a Pass, and + we are operating on Function's.

        + +

        Next we have:

        +
        + using namespace llvm;
        + 
        +

        ... which is required because the functions from the include files + live in the llvm namespace. +

        + +

        Next we have:

        + +
        + namespace {
        + 
        + +

        ... which starts out an anonymous namespace. Anonymous namespaces are to C++ + what the "static" keyword is to C (at global scope). It makes the + things declared inside of the anonymous namespace only visible to the current + file. If you're not familiar with them, consult a decent C++ book for more + information.

        + +

        Next, we declare our pass itself:

        + +
        +   struct Hello : public FunctionPass {
        + 

        + +

        This declares a "Hello" class that is a subclass of FunctionPass. + The different builtin pass subclasses are described in detail later, but for now, know that FunctionPass's operate a function at a + time.

        + +
        +     virtual bool runOnFunction(Function &F) {
        +       std::cerr << "Hello: " << F.getName() << "\n";
        +       return false;
        +     }
        +   };  // end of struct Hello
        + 
        + +

        We declare a "runOnFunction" method, + which overloads an abstract virtual method inherited from FunctionPass. This is where we are supposed + to do our thing, so we just print out our message with the name of each + function.

        + +
        +   RegisterOpt<Hello> X("hello", "Hello World Pass");
        + }  // end of anonymous namespace
        + 
        + +

        Lastly, we register our class Hello, giving it a command line + argument "hello", and a name "Hello World Pass". There are + several different ways of registering your pass, + depending on what it is to be used for. For "optimizations" we use the + RegisterOpt template.

        + +

        As a whole, the .cpp file looks like:

        + +
        + #include "llvm/Pass.h"
        + #include "llvm/Function.h"
        + 
        + using namespace llvm;
        + 
        + namespace {
        +   struct Hello : public FunctionPass {
        +     virtual bool runOnFunction(Function &F) {
        +       std::cerr << "Hello: " << F.getName() << "\n";
        +       return false;
        +     }
        +   };
        +   
        +   RegisterOpt<Hello> X("hello", "Hello World Pass");
        + }
        + 
        + +

        Now that it's all together, compile the file with a simple "gmake" + command in the local directory and you should get a new + "lib/Debug/libhello.so file. Note that everything in this file is + contained in an anonymous namespace: this reflects the fact that passes are self + contained units that do not need external interfaces (although they can have + them) to be useful.

        + +
        + + + + +
        + +

        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.

        + +

        To test it, follow the example at the end of the Getting Started Guide to compile "Hello World" to + LLVM. We can now run the bytecode file (hello.bc) for the program + through our transformation like this (or course, any bytecode file will + work):

        + +
        + $ opt -load ../../../lib/Debug/libhello.so -hello < hello.bc > /dev/null
        + Hello: __main
        + Hello: puts
        + Hello: main
        + 
        + +

        The '-load' option specifies that 'opt' should load your + pass as a shared object, which makes '-hello' a valid command line + argument (which is one reason you need to register your + pass). Because the hello pass does not modify the program in any + interesting way, we just throw away the result of opt (sending it to + /dev/null).

        + +

        To see what happened to the other string you registered, try running + opt with the --help option:

        + +
        + $ opt -load ../../../lib/Debug/libhello.so --help
        + OVERVIEW: llvm .bc -> .bc modular optimizer
        + 
        + USAGE: opt [options] <input bytecode>
        + 
        + OPTIONS:
        +   Optimizations available:
        + ...
        +     -funcresolve    - Resolve Functions
        +     -gcse           - Global Common Subexpression Elimination
        +     -globaldce      - Dead Global Elimination
        +     -hello          - Hello World Pass
        +     -indvars        - Canonicalize Induction Variables
        +     -inline         - Function Integration/Inlining
        +     -instcombine    - Combine redundant instructions
        + ...
        + 
        + +

        The pass name get added as the information string for your pass, giving some + documentation to users of opt. Now that you have a working pass, you + would go ahead and make it do the cool transformations you want. Once you get + it all working and tested, it may become useful to find out how fast your pass + is. The PassManager provides a nice command + line option (--time-passes) that allows you to get information about + the execution time of your pass along with the other passes you queue up. For + example:

        + +
        + $ opt -load ../../../lib/Debug/libhello.so -hello -time-passes < hello.bc > /dev/null
        + Hello: __main
        + Hello: puts
        + Hello: main
        + ===============================================================================
        +                       ... Pass execution timing report ...
        + ===============================================================================
        +   Total Execution Time: 0.02 seconds (0.0479059 wall clock)
        + 
        +    ---User Time---   --System Time--   --User+System--   ---Wall Time---  --- Pass Name ---
        +    0.0100 (100.0%)   0.0000 (  0.0%)   0.0100 ( 50.0%)   0.0402 ( 84.0%)  Bytecode Writer
        +    0.0000 (  0.0%)   0.0100 (100.0%)   0.0100 ( 50.0%)   0.0031 (  6.4%)  Dominator Set Construction
        +    0.0000 (  0.0%)   0.0000 (  0.0%)   0.0000 (  0.0%)   0.0013 (  2.7%)  Module Verifier
        +    0.0000 (  0.0%)   0.0000 (  0.0%)   0.0000 (  0.0%)   0.0033 (  6.9%)  Hello World Pass
        +    0.0100 (100.0%)   0.0100 (100.0%)   0.0200 (100.0%)   0.0479 (100.0%)  TOTAL
        + 
        + +

        As you can see, our implementation above is pretty fast :). The additional + passes listed are automatically inserted by the 'opt' tool to verify + that the LLVM emitted by your pass is still valid and well formed LLVM, which + hasn't been broken somehow.

        + +

        Now that you have seen the basics of the mechanics behind passes, we can talk + about some more details of how they work and how to use them.

        + +
        + + + + + +
        + +

        One of the first things that you should do when designing a new pass is to + decide what class you should subclass for your pass. The Hello World example uses the FunctionPass class for its implementation, but we + did not discuss why or when this should occur. Here we talk about the classes + available, from the most general to the most specific.

        + +

        When choosing a superclass for your Pass, you should choose the most + specific class possible, while still being able to meet the requirements + listed. This gives the LLVM Pass Infrastructure information necessary to + optimize how passes are run, so that the resultant compiler isn't unneccesarily + slow.

        + +
        + + + + +
        + +

        The most plain and boring type of pass is the "ImmutablePass" + class. This pass type is used for passes that do not have to be run, do not + change state, and never need to be updated. This is not a normal type of + transformation or analysis, but can provide information about the current + compiler configuration.

        + +

        Although this pass class is very infrequently used, it is important for + providing information about the current target machine being compiled for, and + other static information that can affect the various transformations.

        + +

        ImmutablePasses never invalidate other transformations, are never + invalidated, and are never "run".

        + +
        + + + + +
        + +

        The "Pass" + class is the most general of all superclasses that you can use. Deriving from + Pass indicates that your pass uses the entire program as a unit, + refering to function bodies in no predictable order, or adding and removing + functions. Because nothing is known about the behavior of direct Pass + subclasses, no optimization can be done for their execution.

        + +

        To write a correct Pass subclass, derive from Pass and + overload the run method with the following signature:

        + +
        + + + + +
        + +
        +   virtual bool run(Module &M) = 0;
        + 
        + +

        The run method performs the interesting work of the pass, and should + return true if the module was modified by the transformation, false + otherwise.

        + +
        + + + + +
        + +

        In contrast to direct Pass subclasses, direct FunctionPass + subclasses do have a predictable, local behavior that can be expected by the + system. All FunctionPass execute on each function in the program + independent of all of the other functions in the program. + FunctionPass's do not require that they are executed in a particular + order, and FunctionPass's do not modify external functions.

        + +

        To be explicit, FunctionPass subclasses are not allowed to:

        + +
          +
        1. Modify a Function other than the one currently being processed.
        2. +
        3. Add or remove Function's from the current Module.
        4. +
        5. Add or remove global variables from the current Module.
        6. +
        7. Maintain state across invocations of + runOnFunction (including global data)
        8. +
        + +

        Implementing a FunctionPass is usually straightforward (See the Hello World pass for example). FunctionPass's + may overload three virtual methods to do their work. All of these methods + should return true if they modified the program, or false if they didn't.

        + +
        + + + + +
        + +
        +   virtual bool doInitialization(Module &M);
        + 
        + +

        The doIninitialize method is allowed to do most of the things that + FunctionPass's are not allowed to do. They can add and remove + functions, get pointers to functions, etc. The doInitialization method + is designed to do simple initialization type of stuff that does not depend on + the functions being processed. The doInitialization method call is not + scheduled to overlap with any other pass executions (thus it should be very + fast).

        + +

        A good example of how this method should be used is the LowerAllocations + pass. This pass converts malloc and free instructions into + platform dependent malloc() and free() function calls. It + uses the doInitialization method to get a reference to the malloc and + free functions that it needs, adding prototypes to the module if necessary.

        + +
        + + + + +
        + +
        +   virtual bool runOnFunction(Function &F) = 0;
        + 

        + +

        The runOnFunction method must be implemented by your subclass to do + the transformation or analysis work of your pass. As usual, a true value should + be returned if the function is modified.

        + +
        + + + + +
        + +
        +   virtual bool doFinalization(Module &M);
        + 
        + +

        The doFinalization method is an infrequently used method that is + called when the pass framework has finished calling runOnFunction for every function in the + program being compiled.

        + +
        + + + + +
        + +

        BasicBlockPass's are just like FunctionPass's, except that they must limit + their scope of inspection and modification to a single basic block at a time. + As such, they are not allowed to do any of the following:

        + +
          +
        1. Modify or inspect any basic blocks outside of the current one
        2. +
        3. Maintain state across invocations of + runOnBasicBlock
        4. +
        5. Modify the constrol flow graph (by altering terminator instructions)
        6. +
        7. Any of the things verboten for + FunctionPasses.
        8. +
        + +

        BasicBlockPasses are useful for traditional local and "peephole" + optimizations. They may override the same doInitialization(Module &) and doFinalization(Module &) methods that FunctionPass's have, but also have the following virtual methods that may also be implemented:

        + +
        + + + + +
        + +
        +   virtual bool doInitialization(Function &F);
        + 
        + +

        The doIninitialize method is allowed to do most of the things that + BasicBlockPass's are not allowed to do, but that + FunctionPass's can. The doInitialization method is designed + to do simple initialization type of stuff that does not depend on the + BasicBlocks being processed. The doInitialization method call is not + scheduled to overlap with any other pass executions (thus it should be very + fast).

        + +
        + + + + +
        + +
        +   virtual bool runOnBasicBlock(BasicBlock &BB) = 0;
        + 
        + +

        Override this function to do the work of the BasicBlockPass. This + function is not allowed to inspect or modify basic blocks other than the + parameter, and are not allowed to modify the CFG. A true value must be returned + if the basic block is modified.

        + +
        + + + + +
        + +
        +   virtual bool doFinalization(Function &F);
        + 
        + +

        The doFinalization method is an infrequently used method that is + called when the pass framework has finished calling runOnBasicBlock for every BasicBlock in the + program being compiled. This can be used to perform per-function + finalization.

        + +
        + + + + +
        + +

        A MachineFunctionPass is a part of the LLVM code generator that + executes on the machine-dependent representation of each LLVM function in the + program. A MachineFunctionPass is also a FunctionPass, so all + the restrictions that apply to a FunctionPass also apply to it. + MachineFunctionPasses also have additional restrictions. In particular, + MachineFunctionPasses are not allowed to do any of the following:

        + +
          +
        1. Modify any LLVM Instructions, BasicBlocks or Functions.
        2. +
        3. Modify a MachineFunction other than the one currently being processed.
        4. +
        5. Add or remove MachineFunctions from the current Module.
        6. +
        7. Add or remove global variables from the current Module.
        8. +
        9. Maintain state across invocations of runOnMachineFunction (including global + data)
        10. +
        + +
        + + + + +
        + +
        +   virtual bool runOnMachineFunction(MachineFunction &MF) = 0;
        + 
        + +

        runOnMachineFunction can be considered the main entry point of a + MachineFunctionPass; that is, you should override this method to do the + work of your MachineFunctionPass.

        + +

        The runOnMachineFunction method is called on every + MachineFunction in a Module, so that the + MachineFunctionPass may perform optimizations on the machine-dependent + representation of the function. If you want to get at the LLVM Function + for the MachineFunction you're working on, use + MachineFunction's getFunction() accessor method -- but + remember, you may not modify the LLVM Function or its contents from a + MachineFunctionPass.

        + +
        + + + + + +
        + +

        In the Hello World example pass we illustrated how + pass registration works, and discussed some of the reasons that it is used and + what it does. Here we discuss how and why passes are registered.

        + +

        Passes can be registered in several different ways. Depending on the general + classification of the pass, you should use one of the following templates to + register the pass:

        + +
          +
        • RegisterOpt - This template should be used when you are + registering a pass that logically should be available for use in the + 'opt' utility.
        • + +
        • RegisterAnalysis - This template should be used when you are + registering a pass that logically should be available for use in the + 'analyze' utility.
        • + +
        • RegisterPass - This is the generic form of the + Register* templates that should be used if you want your pass listed by + multiple or no utilities. This template takes an extra third argument that + specifies which tools it should be listed in. See the PassSupport.h + file for more information.
        • + +
        + +

        Regardless of how you register your pass, you must specify at least two + parameters. The first parameter is the name of the pass that is to be used on + the command line to specify that the pass should be added to a program (for + example opt or analyze). The second argument is the name of + the pass, which is to be used for the --help output of programs, as + well as for debug output generated by the --debug-pass option.

        + +

        If a pass is registered to be used by the analyze utility, you + should implement the virtual print method:

        + +
        + + + + +
        + +
        +   virtual void print(std::ostream &O, const Module *M) const;
        + 
        + +

        The print method must be implemented by "analyses" in order to print + a human readable version of the analysis results. This is useful for debugging + an analysis itself, as well as for other people to figure out how an analysis + works. The analyze tool uses this method to generate its output.

        + +

        The ostream parameter specifies the stream to write the results on, + and the Module parameter gives a pointer to the top level module of the + program that has been analyzed. Note however that this pointer may be null in + certain circumstances (such as calling the Pass::dump() from a + debugger), so it should only be used to enhance debug output, it should not be + depended on.

        + +
        + + + + + +
        + +

        One of the main responsibilities of the PassManager is the make sure + that passes interact with each other correctly. Because PassManager + tries to optimize the execution of passes it must + know how the passes interact with each other and what dependencies exist between + the various passes. To track this, each pass can declare the set of passes that + are required to be executed before the current pass, and the passes which are + invalidated by the current pass.

        + +

        Typically this functionality is used to require that analysis results are + computed before your pass is run. Running arbitrary transformation passes can + invalidate the computed analysis results, which is what the invalidation set + specifies. If a pass does not implement the getAnalysisUsage method, it defaults to not + having any prerequisite passes, and invalidating all other passes.

        + +
        + + + + +
        + +
        +   virtual void getAnalysisUsage(AnalysisUsage &Info) const;
        + 
        + +

        By implementing the getAnalysisUsage method, the required and + invalidated sets may be specified for your transformation. The implementation + should fill in the AnalysisUsage + object with information about which passes are required and not invalidated. To + do this, a pass may call any of the following methods on the AnalysisUsage + object:

        +
        + + + + +
        +

        + If you pass requires a previous pass to be executed (an analysis for example), + it can use one of these methods to arrange for it to be run before your pass. + LLVM has many different types of analyses and passes that can be required, + spaning the range from DominatorSet to BreakCriticalEdges. + requiring BreakCriticalEdges, for example, guarantees that there will + be no critical edges in the CFG when your pass has been run. +

        + +

        + Some analyses chain to other analyses to do their job. For example, an AliasAnalysis implementation is required to chain to other alias analysis passes. In + cases where analyses chain, the addRequiredTransitive method should be + used instead of the addRequired method. This informs the PassManager + that the transitively required pass should be alive as long as the requiring + pass is. +

        +
        + + + + +
        +

        + One of the jobs of the PassManager is to optimize how and when analyses are run. + In particular, it attempts to avoid recomputing data unless it needs to. For + this reason, passes are allowed to declare that they preserve (i.e., they don't + invalidate) an existing analysis if it's available. For example, a simple + constant folding pass would not modify the CFG, so it can't possible effect the + results of dominator analysis. By default, all passes are assumed to invalidate + all others. +

        + +

        + The AnalysisUsage class provides several methods which are useful in + certain circumstances that are related to addPreserved. In particular, + the setPreservesAll method can be called to indicate that the pass does + not modify the LLVM program at all (which is true for analyses), and the + setPreservesCFG method can be used by transformations that change + instructions in the program but do not modify the CFG or terminator instructions + (note that this property is implicitly set for BasicBlockPass's). +

        + +

        + addPreserved is particularly useful for transformations like + BreakCriticalEdges. This pass knows how to update a small set of loop + and dominator related analyses if they exist, so it can preserve them, despite + the fact that it hacks on the CFG. +

        +
        + + + + +
        + +
        +   // This is an example implementation from an analysis, which does not modify
        +   // the program at all, yet has a prerequisite.
        +   void PostDominanceFrontier::getAnalysisUsage(AnalysisUsage &AU) const {
        +     AU.setPreservesAll();
        +     AU.addRequired<PostDominatorTree>();
        +   }
        + 
        + +

        and:

        + +
        +   // This example modifies the program, but does not modify the CFG
        +   void LICM::getAnalysisUsage(AnalysisUsage &AU) const {
        +     AU.setPreservesCFG();
        +     AU.addRequired<LoopInfo>();
        +   }
        + 
        + +
        + + + + +
        + +

        The Pass::getAnalysis<> method is automatically inherited by + your class, providing you with access to the passes that you declared that you + required with the getAnalysisUsage + method. It takes a single template argument that specifies which pass class you + want, and returns a reference to that pass. For example:

        + +
        +    bool LICM::runOnFunction(Function &F) {
        +      LoopInfo &LI = getAnalysis<LoopInfo>();
        +      ...
        +    }
        + 
        + +

        This method call returns a reference to the pass desired. You may get a + runtime assertion failure if you attempt to get an analysis that you did not + declare as required in your getAnalysisUsage implementation. This + method can be called by your run* method implementation, or by any + other local method invoked by your run* method.

        + +

        + If your pass is capable of updating analyses if they exist (e.g., + BreakCriticalEdges, as described above), you can use the + getAnalysisToUpdate method, which returns a pointer to the analysis if + it is active. For example:

        + +
        +   ...
        +   if (DominatorSet *DS = getAnalysisToUpdate<DominatorSet>()) {
        +     // A DominatorSet is active.  This code will update it.
        +   }
        +   ...
        + 
        + +
        + + + + + +
        + +

        Now that we understand the basics of how passes are defined, how the are + used, and how they are required from other passes, it's time to get a little bit + fancier. All of the pass relationships that we have seen so far are very + simple: one pass depends on one other specific pass to be run before it can run. + For many applications, this is great, for others, more flexibility is + required.

        + +

        In particular, some analyses are defined such that there is a single simple + interface to the analysis results, but multiple ways of calculating them. + Consider alias analysis for example. The most trivial alias analysis returns + "may alias" for any alias query. The most sophisticated analysis a + flow-sensitive, context-sensitive interprocedural analysis that can take a + significant amount of time to execute (and obviously, there is a lot of room + between these two extremes for other implementations). To cleanly support + situations like this, the LLVM Pass Infrastructure supports the notion of + Analysis Groups.

        + +
        + + + + +
        + +

        An Analysis Group is a single simple interface that may be implemented by + multiple different passes. Analysis Groups can be given human readable names + just like passes, but unlike passes, they need not derive from the Pass + class. An analysis group may have one or more implementations, one of which is + the "default" implementation.

        + +

        Analysis groups are used by client passes just like other passes are: the + AnalysisUsage::addRequired() and Pass::getAnalysis() methods. + In order to resolve this requirement, the PassManager + scans the available passes to see if any implementations of the analysis group + are available. If none is available, the default implementation is created for + the pass to use. All standard rules for interaction + between passes still apply.

        + +

        Although Pass Registration is optional for normal + passes, all analysis group implementations must be registered, and must use the + RegisterAnalysisGroup template to join the + implementation pool. Also, a default implementation of the interface + must be registered with RegisterAnalysisGroup.

        + +

        As a concrete example of an Analysis Group in action, consider the AliasAnalysis + analysis group. The default implementation of the alias analysis interface (the + basicaa + pass) just does a few simple checks that don't require significant analysis to + compute (such as: two different globals can never alias each other, etc). + Passes that use the AliasAnalysis + interface (for example the gcse pass), do + not care which implementation of alias analysis is actually provided, they just + use the designated interface.

        + +

        From the user's perspective, commands work just like normal. Issuing the + command 'opt -gcse ...' will cause the basicaa class to be + instantiated and added to the pass sequence. Issuing the command 'opt + -somefancyaa -gcse ...' will cause the gcse pass to use the + somefancyaa alias analysis (which doesn't actually exist, it's just a + hypothetical example) instead.

        + +
        + + + + +
        + +

        The RegisterAnalysisGroup template is used to register the analysis + group itself as well as add pass implementations to the analysis group. First, + an analysis should be registered, with a human readable name provided for it. + Unlike registration of passes, there is no command line argument to be specified + for the Analysis Group Interface itself, because it is "abstract":

        + +
        +   static RegisterAnalysisGroup<AliasAnalysis> A("Alias Analysis");
        + 
        + +

        Once the analysis is registered, passes can declare that they are valid + implementations of the interface by using the following code:

        + +
        + namespace {
        +   // Analysis Group implementations must be registered normally...
        +   RegisterOpt<FancyAA>
        +   B("somefancyaa", "A more complex alias analysis implementation");
        + 
        +   // Declare that we implement the AliasAnalysis interface
        +   RegisterAnalysisGroup<AliasAnalysis, FancyAA> C;
        + }
        + 
        + +

        This just shows a class FancyAA that is registered normally, then + uses the RegisterAnalysisGroup template to "join" the AliasAnalysis + analysis group. Every implementation of an analysis group should join using + this template. A single pass may join multiple different analysis groups with + no problem.

        + +
        + namespace {
        +   // Analysis Group implementations must be registered normally...
        +   RegisterOpt<BasicAliasAnalysis>
        +   D("basicaa", "Basic Alias Analysis (default AA impl)");
        + 
        +   // Declare that we implement the AliasAnalysis interface
        +   RegisterAnalysisGroup<AliasAnalysis, BasicAliasAnalysis, true> E;
        + }
        + 
        + +

        Here we show how the default implementation is specified (using the extra + argument to the RegisterAnalysisGroup template). There must be exactly + one default implementation available at all times for an Analysis Group to be + used. Here we declare that the BasicAliasAnalysis + pass is the default implementation for the interface.

        + +
        + + + + + +
        + +

        The PassManager + class + takes a list of passes, ensures their prerequisites + are set up correctly, and then schedules passes to run efficiently. All of the + LLVM tools that run passes use the PassManager for execution of these + passes.

        + +

        The PassManager does two main things to try to reduce the execution + time of a series of passes:

        + +
          +
        1. Share analysis results - The PassManager attempts to avoid + recomputing analysis results as much as possible. This means keeping track of + which analyses are available already, which analyses get invalidated, and which + analyses are needed to be run for a pass. An important part of work is that the + PassManager tracks the exact lifetime of all analysis results, allowing + it to free memory allocated to holding analysis + results as soon as they are no longer needed.
        2. + +
        3. Pipeline the execution of passes on the program - The + PassManager attempts to get better cache and memory usage behavior out + of a series of passes by pipelining the passes together. This means that, given + a series of consequtive FunctionPass's, it + will execute all of the FunctionPass's on + the first function, then all of the FunctionPasses on the second function, + etc... until the entire program has been run through the passes. + +

          This improves the cache behavior of the compiler, because it is only touching + the LLVM program representation for a single function at a time, instead of + traversing the entire program. It reduces the memory consumption of compiler, + because, for example, only one DominatorSet + needs to be calculated at a time. This also makes it possible some interesting enhancements in the future.

        4. + +
        + +

        The effectiveness of the PassManager is influenced directly by how + much information it has about the behaviors of the passes it is scheduling. For + example, the "preserved" set is intentionally conservative in the face of an + unimplemented getAnalysisUsage method. + Not implementing when it should be implemented will have the effect of not + allowing any analysis results to live across the execution of your pass.

        + +

        The PassManager class exposes a --debug-pass command line + options that is useful for debugging pass execution, seeing how things work, and + diagnosing when you should be preserving more analyses than you currently are + (To get information about all of the variants of the --debug-pass + option, just type 'opt --help-hidden').

        + +

        By using the --debug-pass=Structure option, for example, we can see + how our Hello World pass interacts with other passes. + Lets try it out with the gcse and licm passes:

        + +
        + $ opt -load ../../../lib/Debug/libhello.so -gcse -licm --debug-pass=Structure < hello.bc > /dev/null
        + Module Pass Manager
        +   Function Pass Manager
        +     Dominator Set Construction
        +     Immediate Dominators Construction
        +     Global Common Subexpression Elimination
        + --  Immediate Dominators Construction
        + --  Global Common Subexpression Elimination
        +     Natural Loop Construction
        +     Loop Invariant Code Motion
        + --  Natural Loop Construction
        + --  Loop Invariant Code Motion
        +     Module Verifier
        + --  Dominator Set Construction
        + --  Module Verifier
        +   Bytecode Writer
        + --Bytecode Writer
        + 
        + +

        This output shows us when passes are constructed and when the analysis + results are known to be dead (prefixed with '--'). Here we see that + GCSE uses dominator and immediate dominator information to do its job. The LICM + pass uses natural loop information, which uses dominator sets, but not immediate + dominators. Because immediate dominators are no longer useful after the GCSE + pass, it is immediately destroyed. The dominator sets are then reused to + compute natural loop information, which is then used by the LICM pass.

        + +

        After the LICM pass, the module verifier runs (which is automatically added + by the 'opt' tool), which uses the dominator set to check that the + resultant LLVM code is well formed. After it finishes, the dominator set + information is destroyed, after being computed once, and shared by three + passes.

        + +

        Lets see how this changes when we run the Hello + World pass in between the two passes:

        + +
        + $ opt -load ../../../lib/Debug/libhello.so -gcse -hello -licm --debug-pass=Structure < hello.bc > /dev/null
        + Module Pass Manager
        +   Function Pass Manager
        +     Dominator Set Construction
        +     Immediate Dominators Construction
        +     Global Common Subexpression Elimination
        + --  Dominator Set Construction
        + --  Immediate Dominators Construction
        + --  Global Common Subexpression Elimination
        +     Hello World Pass
        + --  Hello World Pass
        +     Dominator Set Construction
        +     Natural Loop Construction
        +     Loop Invariant Code Motion
        + --  Natural Loop Construction
        + --  Loop Invariant Code Motion
        +     Module Verifier
        + --  Dominator Set Construction
        + --  Module Verifier
        +   Bytecode Writer
        + --Bytecode Writer
        + Hello: __main
        + Hello: puts
        + Hello: main
        + 
        + +

        Here we see that the Hello World pass has killed the + Dominator Set pass, even though it doesn't modify the code at all! To fix this, + we need to add the following getAnalysisUsage method to our pass:

        + +
        +     // We don't modify the program, so we preserve all analyses
        +     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
        +       AU.setPreservesAll();
        +     }
        + 
        + +

        Now when we run our pass, we get this output:

        + +
        + $ opt -load ../../../lib/Debug/libhello.so -gcse -hello -licm --debug-pass=Structure < hello.bc > /dev/null
        + Pass Arguments:  -gcse -hello -licm
        + Module Pass Manager
        +   Function Pass Manager
        +     Dominator Set Construction
        +     Immediate Dominators Construction
        +     Global Common Subexpression Elimination
        + --  Immediate Dominators Construction
        + --  Global Common Subexpression Elimination
        +     Hello World Pass
        + --  Hello World Pass
        +     Natural Loop Construction
        +     Loop Invariant Code Motion
        + --  Loop Invariant Code Motion
        + --  Natural Loop Construction
        +     Module Verifier
        + --  Dominator Set Construction
        + --  Module Verifier
        +   Bytecode Writer
        + --Bytecode Writer
        + Hello: __main
        + Hello: puts
        + Hello: main
        + 
        + +

        Which shows that we don't accidentally invalidate dominator information + anymore, and therefore do not have to compute it twice.

        + +
        + + + + +
        + +
        +   virtual void releaseMemory();
        + 
        + +

        The PassManager automatically determines when to compute analysis + results, and how long to keep them around for. Because the lifetime of the pass + object itself is effectively the entire duration of the compilation process, we + need some way to free analysis results when they are no longer useful. The + releaseMemory virtual method is the way to do this.

        + +

        If you are writing an analysis or any other pass that retains a significant + amount of state (for use by another pass which "requires" your pass and uses the + getAnalysis method) you should implement + releaseMEmory to, well, release the memory allocated to maintain this + internal state. This method is called after the run* method for the + class, before the next call of run* in your pass.

        + +
        + + + + + +
        + +

        Unfortunately, using GDB with dynamically loaded passes is not as easy as it + should be. First of all, you can't set a breakpoint in a shared object that has + not been loaded yet, and second of all there are problems with inlined functions + in shared objects. Here are some suggestions to debugging your pass with + GDB.

        + +

        For sake of discussion, I'm going to assume that you are debugging a + transformation invoked by opt, although nothing described here depends + on that.

        + +
        + + + + +
        + +

        First thing you do is start gdb on the opt process:

        + +
        + $ gdb opt
        + GNU gdb 5.0
        + Copyright 2000 Free Software Foundation, Inc.
        + GDB is free software, covered by the GNU General Public License, and you are
        + welcome to change it and/or distribute copies of it under certain conditions.
        + Type "show copying" to see the conditions.
        + There is absolutely no warranty for GDB.  Type "show warranty" for details.
        + This GDB was configured as "sparc-sun-solaris2.6"...
        + (gdb)
        + 
        + +

        Note that opt has a lot of debugging information in it, so it takes + time to load. Be patient. Since we cannot set a breakpoint in our pass yet + (the shared object isn't loaded until runtime), we must execute the process, and + have it stop before it invokes our pass, but after it has loaded the shared + object. The most foolproof way of doing this is to set a breakpoint in + PassManager::run and then run the process with the arguments you + want:

        + +
        + (gdb) break PassManager::run
        + Breakpoint 1 at 0x2413bc: file Pass.cpp, line 70.
        + (gdb) run test.bc -load $(LLVMTOP)/llvm/lib/Debug/[libname].so -[passoption]
        + Starting program: opt test.bc -load $(LLVMTOP)/llvm/lib/Debug/[libname].so -[passoption]
        + Breakpoint 1, PassManager::run (this=0xffbef174, M=@0x70b298) at Pass.cpp:70
        + 70      bool PassManager::run(Module &M) { return PM->run(M); }
        + (gdb)
        + 
        + +

        Once the opt stops in the PassManager::run method you are + now free to set breakpoints in your pass so that you can trace through execution + or do other standard debugging stuff.

        + +
        + + + + +
        + +

        Once you have the basics down, there are a couple of problems that GDB has, + some with solutions, some without.

        + +
          +
        • Inline functions have bogus stack information. In general, GDB does a + pretty good job getting stack traces and stepping through inline functions. + When a pass is dynamically loaded however, it somehow completely loses this + capability. The only solution I know of is to de-inline a function (move it + from the body of a class to a .cpp file).
        • + +
        • Restarting the program breaks breakpoints. After following the information + above, you have succeeded in getting some breakpoints planted in your pass. Nex + thing you know, you restart the program (i.e., you type 'run' again), + and you start getting errors about breakpoints being unsettable. The only way I + have found to "fix" this problem is to delete the breakpoints that are + already set in your pass, run the program, and re-set the breakpoints once + execution stops in PassManager::run.
        • + +
        + +

        Hopefully these tips will help with common case debugging situations. If + you'd like to contribute some tips of your own, just contact Chris.

        + +
        + + + + + +
        + +

        Although the LLVM Pass Infrastructure is very capable as it stands, and does + some nifty stuff, there are things we'd like to add in the future. Here is + where we are going:

        + +
        + + + + +
        + +

        Multiple CPU machines are becoming more common and compilation can never be + fast enough: obviously we should allow for a multithreaded compiler. Because of + the semantics defined for passes above (specifically they cannot maintain state + across invocations of their run* methods), a nice clean way to + implement a multithreaded compiler would be for the PassManager class + to create multiple instances of each pass object, and allow the separate + instances to be hacking on different parts of the program at the same time.

        + +

        This implementation would prevent each of the passes from having to implement + multithreaded constructs, requiring only the LLVM core to have locking in a few + places (for global resources). Although this is a simple extension, we simply + haven't had time (or multiprocessor machines, thus a reason) to implement this. + Despite that, we have kept the LLVM passes SMP ready, and you should too.

        + +
        + + + + +
        + +

        Currently, the PassManager's run method takes a Module + as input, and runs all of the passes on this module. The problem with this + approach is that none of the PassManager features can be used for + timing and debugging the actual loading of the module from disk or + standard input.

        + +

        To solve this problem, eventually the PassManager class will accept + a ModuleSource object instead of a Module itself. When complete, this + will also allow for streaming of functions out of the bytecode representation, + allowing us to avoid holding the entire program in memory at once if we only are + dealing with FunctionPasses.

        + +

        As part of a different issue, eventually the bytecode loader will be extended + to allow on-demand loading of functions from the bytecode representation, in + order to better support the runtime reoptimizer. The bytecode format is already + capable of this, the loader just needs to be reworked a bit.

        + +
        + + + + +
        + +

        Currently it is illegal for a Pass to require a + FunctionPass. This is because there is + only one instance of the FunctionPass + object ever created, thus nowhere to store information for all of the functions + in the program at the same time. Although this has come up a couple of times + before, this has always been worked around by factoring one big complicated pass + into a global and an interprocedural part, both of which are distinct. In the + future, it would be nice to have this though.

        + +

        Note that it is no problem for a FunctionPass to require the results of a Pass, only the other way around.

        + +
        + + +
        +
        + Valid CSS! + Valid HTML 4.01! + + Chris Lattner
        + The LLVM Compiler Infrastructure
        + Last modified: $Date: 2004/08/13 22:03:04 $ +
        + + + From criswell at cs.uiuc.edu Fri Aug 13 17:05:00 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 17:05:00 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/index.html Message-ID: <200408132205.RAA09426@choi.cs.uiuc.edu> Changes in directory llvm-www/releases: index.html updated: 1.19 -> 1.20 --- Log message: Add link to LLVM 1.3 docs. I'll debug this before adding in the real download link. --- Diffs of the changes: (+2 -1) Index: llvm-www/releases/index.html diff -u llvm-www/releases/index.html:1.19 llvm-www/releases/index.html:1.20 --- llvm-www/releases/index.html:1.19 Thu Jul 15 18:18:48 2004 +++ llvm-www/releases/index.html Fri Aug 13 17:04:50 2004 @@ -28,7 +28,7 @@
        -

        LLVM is distributed under the University of +

        LLVM is distributed under the University of Illinois Open Source License, an OSI-approved license.

        @@ -64,6 +64,7 @@
        • Current LLVM documentation
        • +
        • Documentation for LLVM 1.3
        • Documentation for LLVM 1.2
        • Documentation for LLVM 1.1
        • Documentation for LLVM 1.0
        • From criswell at cs.uiuc.edu Fri Aug 13 17:05:59 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 17:05:59 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/docs/doxygen.css llvm.css Message-ID: <200408132205.RAA09448@choi.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3/docs: doxygen.css added (r1.1) llvm.css added (r1.1) --- Log message: Add style sheets. --- Diffs of the changes: (+150 -0) Index: llvm-www/releases/1.3/docs/doxygen.css diff -c /dev/null llvm-www/releases/1.3/docs/doxygen.css:1.1 *** /dev/null Fri Aug 13 17:05:59 2004 --- llvm-www/releases/1.3/docs/doxygen.css Fri Aug 13 17:05:49 2004 *************** *** 0 **** --- 1,90 ---- + BODY { background: white; color: black; font-family: Verdana,Arial,sans-serif; } + H1 { text-align: center; } + H2 { text-align: center; } + H3 { text-align: center; } + CAPTION { font-weight: bold } + A.qindex {} + A.qindexRef {} + A.el { text-decoration: none; font-weight: bold } + A.elRef { font-weight: bold } + A.code { text-decoration: none; font-weight: normal; color: #4444ee } + A.codeRef { font-weight: normal; color: #4444ee } + A:link { + cursor: pointer; + text-decoration: none; + font-weight: bolder; + } + A:visited { + cursor: pointer; + text-decoration: underline; + font-weight: bolder; + } + A:hover { + cursor: pointer; + text-decoration: underline; + font-weight: bolder; + } + A:active { + cursor: pointer; + text-decoration: underline; + font-weight: bolder; + font-style: italic; + } + DL.el { margin-left: -1cm } + DIV.fragment { width: 100%; border: none; background-color: #eeeeee } + DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } + TD.md { background-color: #f2f2ff; font-weight: bold; } + TD.mdname1 { background-color: #f2f2ff; font-weight: bold; color: #602020; } + TD.mdname { background-color: #f2f2ff; font-weight: bold; color: #602020; width: 600px; } + DIV.groupHeader { margin-left: 16px; margin-top: 12px; margin-bottom: 6px; font-weight: bold } + DIV.groupText { margin-left: 16px; font-style: italic; font-size: smaller } + TD.indexkey { + background-color: #eeeeff; + font-weight: bold; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px + } + TD.indexvalue { + background-color: #eeeeff; + font-style: italic; + padding-right : 10px; + padding-top : 2px; + padding-left : 10px; + padding-bottom : 2px; + margin-left : 0px; + margin-right : 0px; + margin-top : 2px; + margin-bottom : 2px + } + span.keyword { color: #008000 } + span.keywordtype { color: #604020 } + span.keywordflow { color: #e08000 } + span.comment { color: #800000 } + span.preprocessor { color: #806020 } + span.stringliteral { color: #002080 } + span.charliteral { color: #008080 } + + .footer { + font-size: 80%; + font-weight: bold; + text-align: center; + vertical-align: middle; + } + .title { + font-size: 25pt; + color: black; background: url("../img/lines.gif"); + font-weight: bold; + border-width: 1px; + border-style: solid none solid none; + text-align: center; + vertical-align: middle; + padding-left: 8pt; + padding-top: 1px; + padding-bottom: 2px + } Index: llvm-www/releases/1.3/docs/llvm.css diff -c /dev/null llvm-www/releases/1.3/docs/llvm.css:1.1 *** /dev/null Fri Aug 13 17:05:59 2004 --- llvm-www/releases/1.3/docs/llvm.css Fri Aug 13 17:05:49 2004 *************** *** 0 **** --- 1,60 ---- + /* + * LLVM website style sheet + */ + + /* Common styles */ + .body { color: black; background: white; margin: 0 0 0 0 } + + /* No borders on image links */ + a:link img, a:visited img {border-style: none} + + address img { float: right; width: 88px; height: 31px; } + address { clear: right; } + + /* + * Documentation + */ + /* Common for title and header */ + .doc_title, .doc_section, .doc_subsection { + color: black; background: url("img/lines.gif"); + font-family: "Georgia,Palatino,Times,Roman"; font-weight: bold; + border-width: 1px; + border-style: solid none solid none; + text-align: center; + vertical-align: middle; + padding-left: 8pt; + padding-top: 1px; + padding-bottom: 2px + } + + .doc_title { text-align: left; font-size: 25pt } + .doc_section { text-align: center; font-size: 22pt; + margin: 20pt 0pt 5pt 0pt; } + .doc_subsection { width: 75%; + text-align: left; font-size: 12pt; padding: 4pt 4pt 4pt 4pt; + margin: 1.5em 0.5em 0.5em 0.5em } + + .doc_subsubsection { margin: 2.0em 0.5em 0.5em 0.5em; + font-weight: bold; font-style: oblique; + border-bottom: 1px solid #999999; font-size: 12pt; + width: 75%; } + .doc_author { text-align: left; font-weight: bold; padding-left: 20pt } + .doc_text { text-align: left; padding-left: 20pt } + + .doc_footer { text-align: left; padding: 0 0 0 0 } + + .doc_red { color: red } + + .doc_table { text-align: center; width: 90%; + padding: 1px 1px 1px 1px; border: 1px; } + + .doc_table_nw { text-align: center; border: 1px; + padding: 1px 1px 1px 1px; } + + .doc_warning { color: red; font-weight: bold } + + .doc_code { border: solid 1px gray; background: #eeeeee; + margin: 0 1em 0 1em; + padding: 0 1em 0 1em; + display:table; + } From criswell at cs.uiuc.edu Fri Aug 13 17:06:25 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 17:06:25 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/docs/img/Debugging.gif lines.gif Message-ID: <200408132206.RAA09469@choi.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3/docs/img: Debugging.gif added (r1.1) lines.gif added (r1.1) --- Log message: Add images. --- Diffs of the changes: (+0 -0) Index: llvm-www/releases/1.3/docs/img/Debugging.gif Index: llvm-www/releases/1.3/docs/img/lines.gif From criswell at cs.uiuc.edu Fri Aug 13 17:07:59 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 17:07:59 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/docs/CommandGuide/index.html Message-ID: <200408132207.RAA09489@choi.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3/docs/CommandGuide: index.html added (r1.1) --- Log message: Adding Command Guide index. --- Diffs of the changes: (+135 -0) Index: llvm-www/releases/1.3/docs/CommandGuide/index.html diff -c /dev/null llvm-www/releases/1.3/docs/CommandGuide/index.html:1.1 *** /dev/null Fri Aug 13 17:07:59 2004 --- llvm-www/releases/1.3/docs/CommandGuide/index.html Fri Aug 13 17:07:48 2004 *************** *** 0 **** --- 1,135 ---- + + + + LLVM Command Guide + + + + +
          + LLVM Command Guide +
          + +
          + +

          These documents are HTML versions of the man pages + for all of the LLVM tools. These pages describe how to use the LLVM commands + and what their options are. Note that these pages do not describe all of the + options available for all tools. To get a complete listing, pass the + --help (general options) or --help-hidden (general+debugging + options) arguments to the tool you are interested in.

          + +
          + + + + + +
          + +
            + +
          • llvm-as - + assemble a human-readable .ll file into bytecode
          • + +
          • llvm-dis - + disassemble a bytecode file into a human-readable .ll file
          • + +
          • opt - + run a series of LLVM-to-LLVM optimizations on a bytecode file
          • + +
          • llc - + generate native machine code for a bytecode file
          • + +
          • lli - + directly run a program compiled to bytecode using a JIT compiler or + interpreter
          • + +
          • llvm-link + link several bytecode files into one
          • + +
          • analyze - + run LLVM analyses on a bytecode file and print the results
          • + +
          • llvm-nm + print out the names and types of symbols in a bytecode file
          • + +
          • llvm-prof - + format raw `llvmprof.out' data into a human-readable report
          • + +
          + +
          + + + + + +
          +
            + +
          • llvmgcc - + GCC-based C front-end for LLVM + +
          • llvmg++ - + GCC-based C++ front-end for LLVM
          • + +
          • gccas - + compile-time optimizer used by llvm-g++ and llvm-gcc
          • + +
          • gccld - + linker and link-time optimizer used by llvm-g++ and llvm-gcc
          • + +
          • stkrc - + front-end compiler for the Stacker + language
          • + +
          + +
          + + + + + + +
          + +
            + +
          • bugpoint - + automatic test-case reducer
          • + +
          • extract - + extract a function from an LLVM bytecode file
          • + +
          • llvm-bcanalyzer - + bytecode analyzer (analyzes the binary encoding itself, not the program it + represents)
          • + +
          + +
          + + + +
          +
          + Valid CSS! + Valid HTML 4.01! + + LLVM Compiler Infrastructure
          + Last modified: $Date: 2004/08/13 22:07:48 $ +
          + + + From criswell at cs.uiuc.edu Fri Aug 13 17:11:21 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 17:11:21 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/docs/CommandGuide/html/ Message-ID: <200408132211.RAA09630@choi.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3/docs/CommandGuide/html: --- Log message: Directory /home/vadve/shared/InternalCVS/llvm-www/releases/1.3/docs/CommandGuide/html added to the repository --- Diffs of the changes: (+0 -0) From criswell at cs.uiuc.edu Fri Aug 13 17:11:35 2004 From: criswell at cs.uiuc.edu (John Criswell) Date: Fri, 13 Aug 2004 17:11:35 -0500 Subject: [llvm-commits] CVS: llvm-www/releases/1.3/docs/CommandGuide/html/analyze.html bugpoint.html extract.html gccas.html gccld.html llc.html lli.html llvm-as.html llvm-bcanalyzer.html llvm-db.html llvm-dis.html llvm-link.html llvm-nm.html llvm-prof.html llvmgcc.html llvmgxx.html manpage.css opt.html stkrc.html Message-ID: <200408132211.RAA09683@choi.cs.uiuc.edu> Changes in directory llvm-www/releases/1.3/docs/CommandGuide/html: analyze.html added (r1.1) bugpoint.html added (r1.1) extract.html added (r1.1) gccas.html added (r1.1) gccld.html added (r1.1) llc.html added (r1.1) lli.html added (r1.1) llvm-as.html added (r1.1) llvm-bcanalyzer.html added (r1.1) llvm-db.html added (r1.1) llvm-dis.html added (r1.1) llvm-link.html added (r1.1) llvm-nm.html added (r1.1) llvm-prof.html added (r1.1) llvmgcc.html added (r1.1) llvmgxx.html added (r1.1) manpage.css added (r1.1) opt.html added (r1.1) stkrc.html added (r1.1) --- Log message: Adding in Command Guide. --- Diffs of the changes: (+2861 -0) Index: llvm-www/releases/1.3/docs/CommandGuide/html/analyze.html diff -c /dev/null llvm-www/releases/1.3/docs/CommandGuide/html/analyze.html:1.1 *** /dev/null Fri Aug 13 17:11:34 2004 --- llvm-www/releases/1.3/docs/CommandGuide/html/analyze.html Fri Aug 13 17:11:24 2004 *************** *** 0 **** --- 1,120 ---- + + + + analyze - LLVM program analyzer + + + + + + +

          + + + + +

          +

          +
          +

          NAME

          +

          analyze - LLVM program analyzer

          +

          +

          +
          +

          SYNOPSIS

          +

          analyze [options] [filename]

          +

          +

          +
          +

          DESCRIPTION

          +

          The analyze command performs various analysis of LLVM assembly + code or bytecode. It will usually print the results on standard + output, but in a few cases, it will print output to standard error + or generate a file with the analysis output, which is usually done + when the output is meant for another program.

          +

          If filename is omitted or is -, analyze reads its input from + standard input. It first attempts to interpret its input as LLVM + bytecode. If it encounters an error, it then attempts to parse the + input as LLVM assembly language.

          +

          +

          +
          +

          OPTIONS

          +
          +
          -help
          +
          +
          + Print a summary of command line options. +
          +

          +
          -q
          +
          +
          + Quiet mode. With this option, analysis pass names are not printed. +
          +

          +
          -load plugin
          +
          +
          + 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. Use + analyze -load plugin -help to see the new list of available + analysis passes.

          +
          +

          +
          -profile-info-file filename
          +
          +
          + Specify the name of the file loaded by the -profile-loader option. +
          +

          +
          -stats
          +
          +
          + Print statistics. +
          +

          +
          -time-passes
          +
          +
          + Record the amount of time needed for each pass and print it to standard + error. +
          +

          +

          +

          +
          +

          EXIT STATUS

          +

          If analyze succeeds, it will exit with 0. Otherwise, if an error + occurs, it will exit with a non-zero value.

          +

          +

          +
          +

          SEE ALSO

          +

          opt

          +

          +

          +
          +

          AUTHORS

          +

          Maintained by the LLVM Team (http://llvm.cs.uiuc.edu).

          + + + + Index: llvm-www/releases/1.3/docs/CommandGuide/html/bugpoint.html diff -c /dev/null llvm-www/releases/1.3/docs/CommandGuide/html/bugpoint.html:1.1 *** /dev/null Fri Aug 13 17:11:34 2004 --- llvm-www/releases/1.3/docs/CommandGuide/html/bugpoint.html Fri Aug 13 17:11:24 2004 *************** *** 0 **** --- 1,309 ---- + + + + bugpoint - automatic test case reduction tool + + + + + + +

          + + + + +

          +

          +
          +

          NAME

          +

          bugpoint - automatic test case reduction tool

          +

          +

          +
          +

          SYNOPSIS

          +

          bugpoint [options] [input LLVM ll/bc files] [LLVM passes] --args + program arguments

          +

          +

          +
          +

          DESCRIPTION

          +

          bugpoint narrows down the source of problems in LLVM tools and passes. It + can be used to debug three types of failures: optimizer crashes, miscompilations + by optimizers, or bad native code generation (including problems in the static + and JIT compilers). It aims to reduce large test cases to small, useful ones. + For example, if gccas crashes while optimizing a file, it will identify the + optimization (or combination of optimizations) that causes the crash, and reduce + the file down to a small example which triggers the crash.

          +

          +

          +

          Design Philosophy

          +

          bugpoint is designed to be a useful tool without requiring any hooks into the + LLVM infrastructure at all. It works with any and all LLVM passes and code + generators, and does not need to ``know'' how they work. Because of this, it may + appear to do stupid things or miss obvious simplifications. bugpoint is also + designed to trade off programmer time for computer time in the + compiler-debugging process; consequently, it may take a long period of + (unattended) time to reduce a test case, but we feel it is still worth it. Note + that bugpoint is generally very quick unless debugging a miscompilation where + each test of the program (which requires executing it) takes a long time.

          +

          +

          +

          Automatic Debugger Selection

          +

          bugpoint reads each .bc or .ll file specified on the command line and + links them together into a single module, called the test program. If any LLVM + passes are specified on the command line, it runs these passes on the test + program. If any of the passes crash, or if they produce malformed output (which + causes the verifier to abort), 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 bugpoint has a reference output for the test + program, it tries 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 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 38 passes.

          +

          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 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, analyze, or llc.

          +

          +

          +

          Code generator debugger

          +

          The code generator debugger attempts to narrow down the amount of code that is + being miscompiled by the selected code generator. To do this, it takes the test + program and partitions it into two pieces: one piece which it compiles with the + C backend (into a shared object), and one piece which it runs with either the + JIT or the static compiler (llc). It uses several techniques to reduce the + amount of code pushed through the LLVM code generator, to reduce the potential + scope of the problem. After it is finished, it emits two bytecode files (called + ``test'' [to be compiled with the code generator] and ``safe'' [to be compiled with + the C backend], respectively), and instructions for reproducing the problem. + The code generator debugger assumes that the C backend produces good code.

          +

          +

          +

          Miscompilation debugger

          +

          The miscompilation debugger works similarly to the code generator debugger. It + works by splitting the test program into two pieces, running the optimizations + specified on one piece, linking the two pieces back together, and then executing + the result. It attempts to narrow down the list of passes to the one (or few) + which are causing the miscompilation, then reduce the portion of the test + program which is being miscompiled. The miscompilation debugger assumes that + the selected code generator is working properly.

          +

          +

          +

          Advice for using bugpoint

          +

          bugpoint can be a remarkably useful tool, but it sometimes works in + non-obvious ways. Here are some hints and tips:

          +
            +
          • + In the code generator and miscompilation debuggers, bugpoint only + works with programs that have deterministic output. Thus, if the program + outputs argv[0], the date, time, or any other ``random'' data, bugpoint may + misinterpret differences in these data, when output, as the result of a + miscompilation. Programs should be temporarily modified to disable outputs that + are likely to vary from run to run. +

            +
          • + In the code generator and miscompilation debuggers, debugging will go faster if + you manually modify the program or its inputs to reduce the runtime, but still + exhibit the problem. +

            +
          • + bugpoint is extremely useful when working on a new optimization: it helps + track down regressions quickly. To avoid having to relink bugpoint every + time you change your optimization, make bugpoint dynamically load + your optimization by using the -load option. +

            +
          • + bugpoint can generate a lot of output and run for a long period of time. It + is often useful to capture the output of the program to file. For example, in + the C shell, you can type: +
            +     bugpoint ... |& tee bugpoint.log
            +

            to get a copy of bugpoint's output in the file bugpoint.log, as well as on + your terminal.

            +

            +
          • + bugpoint cannot debug problems with the LLVM linker. If bugpoint crashes + before you see its All input ok message, you might try running 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

          +
          +
          --additional-so library
          +
          +
          + Load the dynamic shared object library into the test program whenever it is + run. This is useful if you are debugging programs which depend on non-LLVM + libraries (such as the X or curses libraries) to run. +
          +

          +
          --args program args
          +
          +
          + Pass all arguments specified after -args to the test program whenever it runs. + Note that if any of the program args start with a '-', you should use: +
          +
          +
          +     bugpoint [bugpoint args] --args -- [program args]
          +
          +
          +

          The ``--'' right after the --args option tells bugpoint to consider any + options starting with - to be part of the --args option, not as options to + bugpoint itself.

          +
          +

          +
          --tool-args tool args
          +
          +
          + Pass all arguments specified after --tool-args to the LLVM tool under test + (llc, lli, etc.) whenever it runs. You should use this option in the + following way: +
          +
          +
          +     bugpoint [bugpoint args] --tool-args -- [tool args]
          +
          +
          +

          The ``--'' right after the --tool-args option tells bugpoint to consider any + options starting with - to be part of the --tool-args option, not as + options to bugpoint itself. (See --args, above.)

          +
          +

          +
          --check-exit-code={true,false}
          +
          +
          + Assume a non-zero exit code or core dump from the test program is a failure. + Defaults to true. +
          +

          +
          --disable-{dce,simplifycfg}
          +
          +
          + Do not run the specified passes to clean up and reduce the size of the test + program. By default, bugpoint uses these passes internally when attempting to + reduce test programs. If you're trying to find a bug in one of these passes, + bugpoint may crash. +
          +

          +
          --help
          +
          +
          + Print a summary of command line options. +
          +

          +
          --input filename
          +
          +
          + Open filename and redirect the standard input of the test program, whenever + it runs, to come from that file. +
          +

          +
          --load plugin
          +
          +
          + Load the dynamic object plugin into bugpoint itself. This object should + register new optimization passes. Once loaded, the object will add new command + line options to enable various optimizations. To see the new complete list of + optimizations, use the --help and --load options together; for example: +
          +
          +
          +     bugpoint --load myNewPass.so --help
          +
          +

          +
          --output filename
          +
          +
          + Whenever the test program produces output on its standard output stream, it + should match the contents of filename (the ``reference output''). If you + do not use this option, bugpoint will attempt to generate a reference output + by compiling the program with the C backend and running it. +
          +

          +
          --profile-info-file filename
          +
          +
          + Profile file loaded by --profile-loader. +
          +

          +
          --run-{int,jit,llc,cbe}
          +
          +
          + Whenever the test program is compiled, bugpoint should generate code for it + using the specified code generator. These options allow you to choose the + interpreter, the JIT compiler, the static native code compiler, or the C + backend, respectively. +
          +

          +

          +

          +
          +

          EXIT STATUS

          +

          If bugpoint succeeds in finding a problem, it will exit with 0. Otherwise, + if an error occurs, it will exit with a non-zero value.

          +

          +

          +
          +

          SEE ALSO

          +

          opt, analyze

          +

          +

          +
          +

          AUTHOR

          +

          Maintained by the LLVM Team (http://llvm.cs.uiuc.edu).

          + + + + Index: llvm-www/releases/1.3/docs/CommandGuide/html/extract.html diff -c /dev/null llvm-www/releases/1.3/docs/CommandGuide/html/extract.html:1.1 *** /dev/null Fri Aug 13 17:11:34 2004 --- llvm-www/releases/1.3/docs/CommandGuide/html/extract.html Fri Aug 13 17:11:24 2004 *************** *** 0 **** --- 1,115 ---- + + + + extract - extract a function from an LLVM module + + + + + + +

          + + + + +

          +

          +
          +

          NAME

          +

          extract - extract a function from an LLVM module

          +

          +

          +
          +

          SYNOPSIS

          +

          extract [options] --func function-name [filename]

          +

          +

          +
          +

          DESCRIPTION

          +

          The extract command takes the name of a function and extracts it from + the specified LLVM bytecode file. It is primarily used as a debugging tool to + reduce test cases from larger programs that are triggering a bug.

          +

          In addition to extracting the bytecode of the specified function, + extract will also remove unreachable global variables, prototypes, and + unused types.

          +

          The extract command reads its input from standard input if filename is + omitted or if filename is -. The output is always written to standard output, + unless the -o option is specified (see below).

          +

          +

          +
          +

          OPTIONS

          +
          +
          -f
          +
          +
          + Force overwrite. Normally, extract will refuse to overwrite an + output file that already exists. With this option, extract + will overwrite the output file and replace it with new bytecode. +
          +

          +
          --func function-name
          +
          +
          + Extract the function named function-name from the LLVM bytecode. +
          +

          +
          --help
          +
          +
          + Print a summary of command line options. +
          +

          +
          -o filename
          +
          +
          + Specify the output filename. If filename is ``-'' (the default), then + extract sends its output to standard output. +
          +

          +
          --stats
          +
          +
          + Print statistics. +
          +

          +
          --time-passes
          +
          +
          + Record the amount of time needed for each pass and print it to standard + error. +
          +

          +

          +

          +
          +

          EXIT STATUS

          +

          If extract succeeds, it will exit with 0. Otherwise, if an error + occurs, it will exit with a non-zero value.

          +

          +

          +
          +

          SEE ALSO

          +

          bugpoint

          +

          +

          +
          +

          AUTHORS

          +

          Maintained by the LLVM Team (http://llvm.cs.uiuc.edu).

          + + + + Index: llvm-www/releases/1.3/docs/CommandGuide/html/gccas.html diff -c /dev/null llvm-www/releases/1.3/docs/CommandGuide/html/gccas.html:1.1 *** /dev/null Fri Aug 13 17:11:34 2004 --- llvm-www/releases/1.3/docs/CommandGuide/html/gccas.html Fri Aug 13 17:11:24 2004 *************** *** 0 **** --- 1,122 ---- + + + + gccas - optimizing LLVM assembler + + + + + + +

          + + + + +

          +

          +
          +

          NAME

          +

          gccas - optimizing LLVM assembler

          +

          +

          +
          +

          SYNOPSIS

          +

          gccas [options] filename

          +

          +

          +
          +

          DESCRIPTION

          +

          The gccas utility takes an LLVM assembly file generated by the + llvmgcc or llvmg++ front-ends and converts + it into an LLVM bytecode file. It is primarily used by the GCC + front end, and as such, attempts to mimic the interface provided + by the default system assembler so that it can act as a ``drop-in'' + replacement.

          +

          gccas performs a number of optimizations on the input program, + including but not limited to: promotion of stack values to SSA + registers; elimination of dead globals, function arguments, code, + and types; tail-call elimination; loop-invariant code motion; global + common-subexpression elimination; and sparse conditional constant + propagation.

          +

          +

          +
          +

          OPTIONS

          +
          +
          --help
          +
          +
          + Print a summary of command line options. +
          +

          +
          -o filename
          +
          +
          + Specify the name of the output file which will hold the assembled bytecode. +
          +

          +
          --disable-inlining
          +
          +
          + Disable the inlining pass. By default, it is enabled. +
          +

          +
          --disable-opt
          +
          +
          + Disable all assembler-time optimization passes. +
          +

          +
          --stats
          +
          +
          + Print statistics. +
          +

          +
          --time-passes
          +
          +
          + Record the amount of time needed for each pass and print it to standard + error. +
          +

          +
          --verify
          +
          +
          + Verify each pass result. +
          +

          +

          +

          +
          +

          EXIT STATUS

          +

          If gccas succeeds, it will exit with an exit status of 0. + Otherwise, if an error occurs, it will exit with a non-zero exit + status.

          +

          +

          +
          +

          SEE ALSO

          +

          llvm-as, gccld

          +

          +

          +
          +

          AUTHORS

          +

          Maintained by the LLVM Team (http://llvm.cs.uiuc.edu).

          + + + + Index: llvm-www/releases/1.3/docs/CommandGuide/html/gccld.html diff -c /dev/null llvm-www/releases/1.3/docs/CommandGuide/html/gccld.html:1.1 *** /dev/null Fri Aug 13 17:11:34 2004 --- llvm-www/releases/1.3/docs/CommandGuide/html/gccld.html Fri Aug 13 17:11:24 2004 *************** *** 0 **** --- 1,251 ---- + + + + gccld - optimizing LLVM linker + + + + + + +

          + + + + +

          +

          +
          +

          NAME

          +

          gccld - optimizing LLVM linker

          +

          +

          +
          +

          SYNOPSIS

          +

          gccld [options] filename ...

          +

          +

          +
          +

          DESCRIPTION

          +

          The gccld utility takes a set of LLVM bytecode files and links them + together into a single LLVM bytecode file. The output bytecode file can be + another bytecode library or an executable bytecode program. Using additional + options, gccld is able to produce native code executables.

          +

          The gccld utility is primarily used by the the llvmgcc manpage and + llvmg++ front-ends, and as such, attempts to mimic the interface + provided by the default system linker so that it can act as a ``drop-in'' + replacement.

          +

          The gccld tool performs a small set of interprocedural, post-link + optimizations on the program.

          +

          +

          +

          Search Order

          +

          When looking for objects specified on the command line, gccld will search for + the object first in the current directory and then in the directory specified by + the LLVM_LIB_SEARCH_PATH environment variable. If it cannot find the object, + it fails.

          +

          When looking for a library specified with the -l option, gccld first + attempts to load a file with that name from the current directory. If that + fails, it looks for liblibrary.bc, liblibrary.a, or liblibrary.shared + library extension, in that order, in each directory added to the library search + path with the -L option. These directories are searched in the order they + were specified. If the library cannot be located, then gccld looks in the + directory specified by the LLVM_LIB_SEARCH_PATH environment variable. If it + does not find a library there, it fails.

          +

          The shared library extension may be .so, .dyld, .dll, or something + different, depending upon the system.

          +

          The -L option is global. It does not matter where it is specified in the + list of command line arguments; the directory is simply added to the search path + and is applied to all libraries, preceding or succeeding, in the command line.

          +

          +

          +

          Link order

          +

          All object files are linked first in the order they were specified on the + command line. All library files are linked next. Some libraries may not be + linked into the object program; see below.

          +

          +

          +

          Library Linkage

          +

          Object files and static bytecode objects are always linked into the output + file. Library archives (.a files) load only the objects within the archive + that define symbols needed by the output file. Hence, libraries should be + listed after the object files and libraries which need them; otherwise, the + library may not be linked in, and the dependent library will not have its + undefined symbols defined.

          +

          +

          +

          Native code generation

          +

          The gccld program has limited support for native code generation, when + using the -native or -native-cbe options.

          +

          +

          +
          +

          OPTIONS

          +
          +
          -help
          +
          +
          + Print a summary of command line options. +
          +

          +
          -o filename
          +
          +
          + Specify the output filename which will hold the linked bytecode. +
          +

          +
          -stats
          +
          +
          + Print statistics. +
          +

          +
          -time-passes
          +
          +
          + Record the amount of time needed for each pass and print it to standard + error. +
          +

          +
          -verify
          +
          +
          + Verify each pass result. +
          +

          +
          -disable-opt
          +
          +
          + Disable all link-time optimization passes. +
          +

          +
          -disable-inlining
          +
          +
          + Do not run the inliner pass. +
          +

          +
          -Ldirectory
          +
          +
          + Add directory to the list of directories to search when looking for + libraries. +
          +

          +
          -disable-internalize
          +
          +
          + Do not mark all symbols as internal. +
          +

          +
          -internalize-public-api-file filename
          +
          +
          + Preserve the list of symbol names in the file filename. +
          +

          +
          -internalize-public-api-list &lt;list&gt;
          +
          +
          + Preserve the symbol names in list. +
          +

          +
          -llibrary
          +
          +
          + Specify libraries to include when linking the output file. When linking, + gccld will first attempt to load a file with the pathname library. If + that fails, it will then attempt to load liblibrary.bc, liblibrary.a, and + liblibrary.shared library extension, in that order. +
          +

          +
          -link-as-library
          +
          +
          + Link the .bc files together as a library, not an executable. +
          +

          +
          -native
          +
          +
          + Generate a native machine code executable. +
          +
          +

          When generating native executables, gccld first checks for a bytecode + version of the library and links it in, if necessary. If the library is + missing, gccld skips it. Then, gccld links in the same + libraries as native code.

          +
          +
          +

          In this way, gccld should be able to link in optimized bytecode + subsets of common libraries and then link in any part of the library that + hasn't been converted to bytecode.

          +
          +

          +
          -native-cbe
          +
          +
          + Generate a native machine code executable with the LLVM C backend. + +
          +
          +
          + 
          + This option is identical to the B<-native> option, but uses the
          + C backend to generate code for the program instead of an LLVM native
          + code generator.
          +
          +

          +
          -s
          +
          +
          + Strip symbol information from the generated executable. +
          +

          +
          -v
          +
          +
          + Print information about actions taken. +
          +

          +

          +

          +
          +

          EXIT STATUS

          +

          If gccld succeeds, it will exit with an exit status of 0. + Otherwise, if an error occurs, it will exit with a non-zero exit + status.

          +

          +

          +
          +

          SEE ALSO

          +

          llvm-link, gccas

          +

          +

          +
          +

          AUTHORS

          +

          Maintained by the LLVM Team (http://llvm.cs.uiuc.edu).

          + + + + Index: llvm-www/releases/1.3/docs/CommandGuide/html/llc.html diff -c /dev/null llvm-www/releases/1.3/docs/CommandGuide/html/llc.html:1.1 *** /dev/null Fri Aug 13 17:11:35 2004 --- llvm-www/releases/1.3/docs/CommandGuide/html/llc.html Fri Aug 13 17:11:24 2004 *************** *** 0 **** --- 1,266 ---- + + + + llc - LLVM static compiler + + + + + + +