diff options
author | dim <dim@FreeBSD.org> | 2014-03-26 07:42:43 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2014-03-26 07:42:43 +0000 |
commit | 45ae227ed48f53447b0000be4c2f1cb142fa5237 (patch) | |
tree | 2c3d1790f54e2af0e10eeb88cb26a0d91f029053 | |
parent | fb422e6d310915f9e2641190198698d922f7ef58 (diff) | |
download | FreeBSD-src-45ae227ed48f53447b0000be4c2f1cb142fa5237.zip FreeBSD-src-45ae227ed48f53447b0000be4c2f1cb142fa5237.tar.gz |
MFC r263312:
Pull in r196939 from upstream llvm trunk (by Reid Kleckner):
Reland "Fix miscompile of MS inline assembly with stack realignment"
This re-lands commit r196876, which was reverted in r196879.
The tests have been fixed to pass on platforms with a stack alignment
larger than 4.
Update to clang side tests will land shortly.
Pull in r196986 from upstream llvm trunk (by Reid Kleckner):
Revert the backend fatal error from r196939
The combination of inline asm, stack realignment, and dynamic allocas
turns out to be too common to reject out of hand.
ASan inserts empy inline asm fragments and uses aligned allocas.
Compiling any trivial function containing a dynamic alloca with ASan is
enough to trigger the check.
XFAIL the test cases that would be miscompiled and add one that uses the
relevant functionality.
Pull in r202930 from upstream llvm trunk (by Hans Wennborg):
Check for dynamic allocas and inline asm that clobbers sp before building
selection dag (PR19012)
In X86SelectionDagInfo::EmitTargetCodeForMemcpy we check with MachineFrameInfo
to make sure that ESI isn't used as a base pointer register before we choose to
emit rep movs (which clobbers esi).
The problem is that MachineFrameInfo wouldn't know about dynamic allocas or
inline asm that clobbers the stack pointer until SelectionDAGBuilder has
encountered them.
This patch fixes the problem by checking for such things when building the
FunctionLoweringInfo.
Differential Revision: http://llvm-reviews.chandlerc.com/D2954
Together, these commits fix the problem encountered in the devel/emacs
port on the i386 architecture, where a combination of stack realignment,
alloca() and memcpy() could incidentally clobber the %esi register,
leading to segfaults in the temacs build-time utility.
See also: http://llvm.org/PR18171 and http://llvm.org/PR19012
Reported by: ashish
PR: ports/183064
MFC r263313:
Pull in r203311 from upstream llvm trunk (by Arnold Schwaighofer):
ISel: Make VSELECT selection terminate in cases where the condition type has to
be split and the result type widened.
When the condition of a vselect has to be split it makes no sense widening the
vselect and thereby widening the condition. We end up in an endless loop of
widening (vselect result type) and splitting (condition mask type) doing this.
Instead, split both the condition and the vselect and widen the result.
I ran this over the test suite with i686 and mattr=+sse and saw no regressions.
Fixes PR18036.
With this fix the original problem case from the graphics/rawtherapee
port (posted in http://llvm.org/PR18036 ) now compiles within ~97MB RSS.
Reported by: mandree
MFC r263320:
Add separate patch files for all the customizations we have currently
applied to our copy of llvm/clang. These can be applied in alphabetical
order to a pristine llvm/clang 3.4 release source tree, to result in the
same version used in FreeBSD.
This is intended to clearly document all the changes until now, which
mostly consist of cherry pickings from the respective upstream trunks,
plus a number of hand-written FreeBSD-specific ones. Hopefully those
can eventually be cleaned up and sent upstream too.
111 files changed, 16451 insertions, 36 deletions
diff --git a/contrib/llvm/include/llvm/CodeGen/FunctionLoweringInfo.h b/contrib/llvm/include/llvm/CodeGen/FunctionLoweringInfo.h index 50d320f..854cac2 100644 --- a/contrib/llvm/include/llvm/CodeGen/FunctionLoweringInfo.h +++ b/contrib/llvm/include/llvm/CodeGen/FunctionLoweringInfo.h @@ -41,6 +41,7 @@ class MachineBasicBlock; class MachineFunction; class MachineModuleInfo; class MachineRegisterInfo; +class SelectionDAG; class TargetLowering; class Value; @@ -125,7 +126,7 @@ public: /// set - Initialize this FunctionLoweringInfo with the given Function /// and its associated MachineFunction. /// - void set(const Function &Fn, MachineFunction &MF); + void set(const Function &Fn, MachineFunction &MF, SelectionDAG *DAG); /// clear - Clear out all the function-specific state. This returns this /// FunctionLoweringInfo to an empty state, ready to be used for a diff --git a/contrib/llvm/include/llvm/CodeGen/MachineFrameInfo.h b/contrib/llvm/include/llvm/CodeGen/MachineFrameInfo.h index 022634d..ba536e7 100644 --- a/contrib/llvm/include/llvm/CodeGen/MachineFrameInfo.h +++ b/contrib/llvm/include/llvm/CodeGen/MachineFrameInfo.h @@ -223,6 +223,10 @@ class MachineFrameInfo { /// Whether the "realign-stack" option is on. bool RealignOption; + /// True if the function includes inline assembly that adjusts the stack + /// pointer. + bool HasInlineAsmWithSPAdjust; + const TargetFrameLowering *getFrameLowering() const; public: explicit MachineFrameInfo(const TargetMachine &TM, bool RealignOpt) @@ -240,6 +244,7 @@ public: LocalFrameSize = 0; LocalFrameMaxAlign = 0; UseLocalStackAllocationBlock = false; + HasInlineAsmWithSPAdjust = false; } /// hasStackObjects - Return true if there are any stack objects in this @@ -451,6 +456,10 @@ public: bool hasCalls() const { return HasCalls; } void setHasCalls(bool V) { HasCalls = V; } + /// Returns true if the function contains any stack-adjusting inline assembly. + bool hasInlineAsmWithSPAdjust() const { return HasInlineAsmWithSPAdjust; } + void setHasInlineAsmWithSPAdjust(bool B) { HasInlineAsmWithSPAdjust = B; } + /// getMaxCallFrameSize - Return the maximum size of a call frame that must be /// allocated for an outgoing function call. This is only available if /// CallFrameSetup/Destroy pseudo instructions are used by the target, and @@ -521,7 +530,7 @@ public: /// variable sized object is created, whether or not the index returned is /// actually used. /// - int CreateVariableSizedObject(unsigned Alignment); + int CreateVariableSizedObject(unsigned Alignment, const AllocaInst *Alloca); /// getCalleeSavedInfo - Returns a reference to call saved info vector for the /// current function. diff --git a/contrib/llvm/include/llvm/CodeGen/MachineFunction.h b/contrib/llvm/include/llvm/CodeGen/MachineFunction.h index c886e25..43b370c 100644 --- a/contrib/llvm/include/llvm/CodeGen/MachineFunction.h +++ b/contrib/llvm/include/llvm/CodeGen/MachineFunction.h @@ -131,8 +131,8 @@ class MachineFunction { /// about the control flow of such functions. bool ExposesReturnsTwice; - /// True if the function includes MS-style inline assembly. - bool HasMSInlineAsm; + /// True if the function includes any inline assembly. + bool HasInlineAsm; MachineFunction(const MachineFunction &) LLVM_DELETED_FUNCTION; void operator=(const MachineFunction&) LLVM_DELETED_FUNCTION; @@ -218,15 +218,14 @@ public: ExposesReturnsTwice = B; } - /// Returns true if the function contains any MS-style inline assembly. - bool hasMSInlineAsm() const { - return HasMSInlineAsm; + /// Returns true if the function contains any inline assembly. + bool hasInlineAsm() const { + return HasInlineAsm; } - /// Set a flag that indicates that the function contains MS-style inline - /// assembly. - void setHasMSInlineAsm(bool B) { - HasMSInlineAsm = B; + /// Set a flag that indicates that the function contains inline assembly. + void setHasInlineAsm(bool B) { + HasInlineAsm = B; } /// getInfo - Keep track of various per-function pieces of information for diff --git a/contrib/llvm/lib/CodeGen/MachineFunction.cpp b/contrib/llvm/lib/CodeGen/MachineFunction.cpp index 0703df0..f3be318 100644 --- a/contrib/llvm/lib/CodeGen/MachineFunction.cpp +++ b/contrib/llvm/lib/CodeGen/MachineFunction.cpp @@ -525,13 +525,14 @@ int MachineFrameInfo::CreateSpillStackObject(uint64_t Size, /// variable sized object is created, whether or not the index returned is /// actually used. /// -int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment) { +int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment, + const AllocaInst *Alloca) { HasVarSizedObjects = true; Alignment = clampStackAlignment(!getFrameLowering()->isStackRealignable() || !RealignOption, Alignment, getFrameLowering()->getStackAlignment()); - Objects.push_back(StackObject(0, Alignment, 0, false, false, true, 0)); + Objects.push_back(StackObject(0, Alignment, 0, false, false, true, Alloca)); ensureMaxAlignment(Alignment); return (int)Objects.size()-NumFixedObjects-1; } diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index 4309dc1..e9d2324 100644 --- a/contrib/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -33,6 +33,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Target/TargetInstrInfo.h" +#include "llvm/Target/TargetFrameLowering.h" #include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetRegisterInfo.h" @@ -55,7 +56,8 @@ static bool isUsedOutsideOfDefiningBlock(const Instruction *I) { return false; } -void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf) { +void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, + SelectionDAG *DAG) { const TargetLowering *TLI = TM.getTargetLowering(); Fn = &fn; @@ -100,6 +102,43 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf) { for (; BB != EB; ++BB) for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); I != E; ++I) { + // Look for dynamic allocas. + if (const AllocaInst *AI = dyn_cast<AllocaInst>(I)) { + if (!AI->isStaticAlloca()) { + unsigned Align = std::max( + (unsigned)TLI->getDataLayout()->getPrefTypeAlignment( + AI->getAllocatedType()), + AI->getAlignment()); + unsigned StackAlign = TM.getFrameLowering()->getStackAlignment(); + if (Align <= StackAlign) + Align = 0; + // Inform the Frame Information that we have variable-sized objects. + MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1, AI); + } + } + + // Look for inline asm that clobbers the SP register. + if (isa<CallInst>(I) || isa<InvokeInst>(I)) { + ImmutableCallSite CS(I); + if (const InlineAsm *IA = dyn_cast<InlineAsm>(CS.getCalledValue())) { + unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); + std::vector<TargetLowering::AsmOperandInfo> Ops = + TLI->ParseConstraints(CS); + for (size_t I = 0, E = Ops.size(); I != E; ++I) { + TargetLowering::AsmOperandInfo &Op = Ops[I]; + if (Op.Type == InlineAsm::isClobber) { + // Clobbers don't have SDValue operands, hence SDValue(). + TLI->ComputeConstraintToUse(Op, SDValue(), DAG); + std::pair<unsigned, const TargetRegisterClass*> PhysReg = + TLI->getRegForInlineAsmConstraint(Op.ConstraintCode, + Op.ConstraintVT); + if (PhysReg.first == SP) + MF->getFrameInfo()->setHasInlineAsmWithSPAdjust(true); + } + } + } + } + // Mark values used outside their block as exported, by allocating // a virtual register for them. if (isUsedOutsideOfDefiningBlock(I)) diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp index f7a3e3d..5f4ff75 100644 --- a/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -2180,6 +2180,17 @@ SDValue DAGTypeLegalizer::WidenVecRes_SELECT(SDNode *N) { if (getTypeAction(CondVT) == TargetLowering::TypeWidenVector) Cond1 = GetWidenedVector(Cond1); + // If we have to split the condition there is no point in widening the + // select. This would result in an cycle of widening the select -> + // widening the condition operand -> splitting the condition operand -> + // splitting the select -> widening the select. Instead split this select + // further and widen the resulting type. + if (getTypeAction(CondVT) == TargetLowering::TypeSplitVector) { + SDValue SplitSelect = SplitVecOp_VSELECT(N, 0); + SDValue Res = ModifyToType(SplitSelect, WidenVT); + return Res; + } + if (Cond1.getValueType() != CondWidenVT) Cond1 = ModifyToType(Cond1, CondWidenVT); } diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 2b2713d..41662a9 100644 --- a/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -851,12 +851,20 @@ void RegsForValue::AddInlineAsmOperands(unsigned Code, bool HasMatching, SDValue Res = DAG.getTargetConstant(Flag, MVT::i32); Ops.push_back(Res); + unsigned SP = TLI.getStackPointerRegisterToSaveRestore(); for (unsigned Value = 0, Reg = 0, e = ValueVTs.size(); Value != e; ++Value) { unsigned NumRegs = TLI.getNumRegisters(*DAG.getContext(), ValueVTs[Value]); MVT RegisterVT = RegVTs[Value]; for (unsigned i = 0; i != NumRegs; ++i) { assert(Reg < Regs.size() && "Mismatch in # registers expected"); - Ops.push_back(DAG.getRegister(Regs[Reg++], RegisterVT)); + unsigned TheReg = Regs[Reg++]; + Ops.push_back(DAG.getRegister(TheReg, RegisterVT)); + + if (TheReg == SP && Code == InlineAsm::Kind_Clobber) { + // If we clobbered the stack pointer, MFI should know about it. + assert(DAG.getMachineFunction().getFrameInfo()-> + hasInlineAsmWithSPAdjust()); + } } } } @@ -3370,9 +3378,7 @@ void SelectionDAGBuilder::visitAlloca(const AllocaInst &I) { setValue(&I, DSA); DAG.setRoot(DSA.getValue(1)); - // Inform the Frame Information that we have just allocated a variable-sized - // object. - FuncInfo.MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1); + assert(FuncInfo.MF->getFrameInfo()->hasVarSizedObjects()); } void SelectionDAGBuilder::visitLoad(const LoadInst &I) { diff --git a/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 3a0cfa1..b8b4db4 100644 --- a/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/contrib/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -419,7 +419,7 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { SplitCriticalSideEffectEdges(const_cast<Function&>(Fn), this); CurDAG->init(*MF, TTI, TLI); - FuncInfo->set(Fn, *MF); + FuncInfo->set(Fn, *MF, CurDAG); if (UseMBPI && OptLevel != CodeGenOpt::None) FuncInfo->BPI = &getAnalysis<BranchProbabilityInfo>(); @@ -428,7 +428,8 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { SDB->init(GFI, *AA, LibInfo); - MF->setHasMSInlineAsm(false); + MF->setHasInlineAsm(false); + SelectAllBasicBlocks(Fn); // If the first basic block in the function has live ins that need to be @@ -511,7 +512,7 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); I != E; ++I) { - if (MFI->hasCalls() && MF->hasMSInlineAsm()) + if (MFI->hasCalls() && MF->hasInlineAsm()) break; const MachineBasicBlock *MBB = I; @@ -522,8 +523,8 @@ bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) { II->isStackAligningInlineAsm()) { MFI->setHasCalls(true); } - if (II->isMSInlineAsm()) { - MF->setHasMSInlineAsm(true); + if (II->isInlineAsm()) { + MF->setHasInlineAsm(true); } } } diff --git a/contrib/llvm/lib/MC/MCParser/AsmParser.cpp b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp index a91bd93..8fe39c8 100644 --- a/contrib/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp @@ -4192,6 +4192,11 @@ bool AsmParser::parseMSInlineAsm( AsmStrRewrites.push_back(AsmRewrite(AOK_Input, Start, SymName.size())); } } + + // Consider implicit defs to be clobbers. Think of cpuid and push. + const uint16_t *ImpDefs = Desc.getImplicitDefs(); + for (unsigned I = 0, E = Desc.getNumImplicitDefs(); I != E; ++I) + ClobberRegs.push_back(ImpDefs[I]); } // Set the number of Outputs and Inputs. diff --git a/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp b/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp index a06ba9d..0d76534 100644 --- a/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/contrib/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -50,7 +50,7 @@ bool X86FrameLowering::hasFP(const MachineFunction &MF) const { return (MF.getTarget().Options.DisableFramePointerElim(MF) || RegInfo->needsStackRealignment(MF) || MFI->hasVarSizedObjects() || - MFI->isFrameAddressTaken() || MF.hasMSInlineAsm() || + MFI->isFrameAddressTaken() || MFI->hasInlineAsmWithSPAdjust() || MF.getInfo<X86MachineFunctionInfo>()->getForceFramePointer() || MMI.callsUnwindInit() || MMI.callsEHReturn()); } diff --git a/contrib/llvm/lib/Target/X86/X86RegisterInfo.cpp b/contrib/llvm/lib/Target/X86/X86RegisterInfo.cpp index dbda556..e6cd593 100644 --- a/contrib/llvm/lib/Target/X86/X86RegisterInfo.cpp +++ b/contrib/llvm/lib/Target/X86/X86RegisterInfo.cpp @@ -403,18 +403,15 @@ bool X86RegisterInfo::hasBasePointer(const MachineFunction &MF) const { if (!EnableBasePointer) return false; - // When we need stack realignment and there are dynamic allocas, we can't - // reference off of the stack pointer, so we reserve a base pointer. - // - // This is also true if the function contain MS-style inline assembly. We - // do this because if any stack changes occur in the inline assembly, e.g., - // "pusha", then any C local variable or C argument references in the - // inline assembly will be wrong because the SP is not properly tracked. - if ((needsStackRealignment(MF) && MFI->hasVarSizedObjects()) || - MF.hasMSInlineAsm()) - return true; - - return false; + // When we need stack realignment, we can't address the stack from the frame + // pointer. When we have dynamic allocas or stack-adjusting inline asm, we + // can't address variables from the stack pointer. MS inline asm can + // reference locals while also adjusting the stack pointer. When we can't + // use both the SP and the FP, we need a separate base pointer register. + bool CantUseFP = needsStackRealignment(MF); + bool CantUseSP = + MFI->hasVarSizedObjects() || MFI->hasInlineAsmWithSPAdjust(); + return CantUseFP && CantUseSP; } bool X86RegisterInfo::canRealignStack(const MachineFunction &MF) const { diff --git a/contrib/llvm/patches/README.TXT b/contrib/llvm/patches/README.TXT new file mode 100644 index 0000000..b9ad69c --- /dev/null +++ b/contrib/llvm/patches/README.TXT @@ -0,0 +1,16 @@ +This is a set of individual patches, which contain all the customizations to +llvm/clang currently in the FreeBSD base system. These can be applied in +alphabetical order to a pristine llvm/clang 3.4 release source tree, for example +by doing: + +svn co https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_34/final llvm-3.4-final +svn co https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_34/final llvm-3.4-final/tools/clang +cd llvm-3.4-final +for p in /usr/src/contrib/llvm/patches/patch-*.diff; do + patch -p0 -f -F0 -E -i $p -s || break +done + +A number of these consist of hand-written modifications, specifically for +FreeBSD, while most others are cherry pickings off the llvm and clang trunks. +When a new version of llvm/clang is eventually imported, those latter ones will +largely disappear. diff --git a/contrib/llvm/patches/patch-r208961-clang-version-include.diff b/contrib/llvm/patches/patch-r208961-clang-version-include.diff new file mode 100644 index 0000000..fb0ac18 --- /dev/null +++ b/contrib/llvm/patches/patch-r208961-clang-version-include.diff @@ -0,0 +1,39 @@ +This patch adjusts clang's default include paths to add FreeBSD-specific +directories. + +Introduced here: http://svn.freebsd.org/changeset/base/208961 + +Index: tools/clang/lib/Frontend/InitHeaderSearch.cpp +=================================================================== +--- tools/clang/lib/Frontend/InitHeaderSearch.cpp ++++ tools/clang/lib/Frontend/InitHeaderSearch.cpp +@@ -14,6 +14,7 @@ + #include "clang/Frontend/Utils.h" + #include "clang/Basic/FileManager.h" + #include "clang/Basic/LangOptions.h" ++#include "clang/Basic/Version.h" + #include "clang/Config/config.h" // C_INCLUDE_DIRS + #include "clang/Lex/HeaderSearch.h" + #include "clang/Lex/HeaderSearchOptions.h" +@@ -333,6 +334,9 @@ void InitHeaderSearch::AddDefaultCIncludePaths(con + #endif + } + break; ++ case llvm::Triple::FreeBSD: ++ AddPath("/usr/include/clang/" CLANG_VERSION_STRING, System, false); ++ break; + + default: + break; +@@ -423,11 +427,6 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple + else + AddPath("/usr/include/c++/4.4", CXXSystem, false); + break; +- case llvm::Triple::FreeBSD: +- // FreeBSD 8.0 +- // FreeBSD 7.3 +- AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple); +- break; + case llvm::Triple::OpenBSD: { + std::string t = triple.getTriple(); + if (t.substr(0, 6) == "x86_64") diff --git a/contrib/llvm/patches/patch-r208987-format-extensions.diff b/contrib/llvm/patches/patch-r208987-format-extensions.diff new file mode 100644 index 0000000..b01553e --- /dev/null +++ b/contrib/llvm/patches/patch-r208987-format-extensions.diff @@ -0,0 +1,214 @@ +This patch adds support for the FreeBSD-specific -fformat-extension option, +which enables additional printf modifiers for the kernel. + +Introduced here: http://svn.freebsd.org/changeset/base/208987 + +Index: tools/clang/lib/Frontend/CompilerInvocation.cpp +=================================================================== +--- tools/clang/lib/Frontend/CompilerInvocation.cpp ++++ tools/clang/lib/Frontend/CompilerInvocation.cpp +@@ -1319,6 +1319,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgLi + Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); + Opts.ShortEnums = Args.hasArg(OPT_fshort_enums); + Opts.Freestanding = Args.hasArg(OPT_ffreestanding); ++ Opts.FormatExtensions = Args.hasArg(OPT_fformat_extensions); + Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; + Opts.NoMathBuiltin = Args.hasArg(OPT_fno_math_builtin); + Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new); +Index: tools/clang/lib/Analysis/FormatString.cpp +=================================================================== +--- tools/clang/lib/Analysis/FormatString.cpp ++++ tools/clang/lib/Analysis/FormatString.cpp +@@ -548,6 +548,11 @@ const char *ConversionSpecifier::toString() const + // Objective-C specific specifiers. + case ObjCObjArg: return "@"; + ++ // FreeBSD specific specifiers. ++ case FreeBSDbArg: return "b"; ++ case FreeBSDDArg: return "D"; ++ case FreeBSDrArg: return "r"; ++ + // GlibC specific specifiers. + case PrintErrno: return "m"; + } +@@ -626,6 +631,7 @@ bool FormatSpecifier::hasValidLengthModifier(const + case ConversionSpecifier::xArg: + case ConversionSpecifier::XArg: + case ConversionSpecifier::nArg: ++ case ConversionSpecifier::FreeBSDrArg: + return true; + default: + return false; +@@ -654,6 +660,7 @@ bool FormatSpecifier::hasValidLengthModifier(const + case ConversionSpecifier::nArg: + case ConversionSpecifier::cArg: + case ConversionSpecifier::sArg: ++ case ConversionSpecifier::FreeBSDrArg: + case ConversionSpecifier::ScanListArg: + return true; + default: +@@ -774,6 +781,9 @@ bool FormatSpecifier::hasStandardConversionSpecifi + case ConversionSpecifier::SArg: + return LangOpt.ObjC1 || LangOpt.ObjC2; + case ConversionSpecifier::InvalidSpecifier: ++ case ConversionSpecifier::FreeBSDbArg: ++ case ConversionSpecifier::FreeBSDDArg: ++ case ConversionSpecifier::FreeBSDrArg: + case ConversionSpecifier::PrintErrno: + case ConversionSpecifier::DArg: + case ConversionSpecifier::OArg: +Index: tools/clang/lib/Analysis/PrintfFormatString.cpp +=================================================================== +--- tools/clang/lib/Analysis/PrintfFormatString.cpp ++++ tools/clang/lib/Analysis/PrintfFormatString.cpp +@@ -198,10 +198,25 @@ static PrintfSpecifierResult ParsePrintfSpecifier( + case '@': k = ConversionSpecifier::ObjCObjArg; break; + // Glibc specific. + case 'm': k = ConversionSpecifier::PrintErrno; break; ++ // FreeBSD format extensions ++ case 'b': ++ if (LO.FormatExtensions) ++ k = ConversionSpecifier::FreeBSDbArg; // int followed by char * ++ break; ++ case 'r': ++ if (LO.FormatExtensions) ++ k = ConversionSpecifier::FreeBSDrArg; ++ break; ++ case 'y': ++ if (LO.FormatExtensions) ++ k = ConversionSpecifier::iArg; ++ break; + // Apple-specific + case 'D': + if (Target.getTriple().isOSDarwin()) + k = ConversionSpecifier::DArg; ++ else if (LO.FormatExtensions) ++ k = ConversionSpecifier::FreeBSDDArg; // u_char * followed by char * + break; + case 'O': + if (Target.getTriple().isOSDarwin()) +@@ -216,6 +231,10 @@ static PrintfSpecifierResult ParsePrintfSpecifier( + FS.setConversionSpecifier(CS); + if (CS.consumesDataArgument() && !FS.usesPositionalArg()) + FS.setArgIndex(argIndex++); ++ // FreeBSD extension ++ if (k == ConversionSpecifier::FreeBSDbArg || ++ k == ConversionSpecifier::FreeBSDDArg) ++ argIndex++; + + if (k == ConversionSpecifier::InvalidSpecifier) { + // Assume the conversion takes one argument. +@@ -618,6 +637,7 @@ bool PrintfSpecifier::hasValidPlusPrefix() const { + case ConversionSpecifier::GArg: + case ConversionSpecifier::aArg: + case ConversionSpecifier::AArg: ++ case ConversionSpecifier::FreeBSDrArg: + return true; + + default: +@@ -643,6 +663,7 @@ bool PrintfSpecifier::hasValidAlternativeForm() co + case ConversionSpecifier::FArg: + case ConversionSpecifier::gArg: + case ConversionSpecifier::GArg: ++ case ConversionSpecifier::FreeBSDrArg: + return true; + + default: +Index: tools/clang/lib/Sema/SemaChecking.cpp +=================================================================== +--- tools/clang/lib/Sema/SemaChecking.cpp ++++ tools/clang/lib/Sema/SemaChecking.cpp +@@ -2980,6 +2980,40 @@ CheckPrintfHandler::HandlePrintfSpecifier(const an + CoveredArgs.set(argIndex); + } + ++ // FreeBSD extensions ++ if (CS.getKind() == ConversionSpecifier::FreeBSDbArg || ++ CS.getKind() == ConversionSpecifier::FreeBSDDArg) { ++ // claim the second argument ++ CoveredArgs.set(argIndex + 1); ++ ++ // Now type check the data expression that matches the ++ // format specifier. ++ const Expr *Ex = getDataArg(argIndex); ++ const analyze_printf::ArgType &AT = ++ (CS.getKind() == ConversionSpecifier::FreeBSDbArg) ? ++ ArgType(S.Context.IntTy) : ArgType::CStrTy; ++ if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) ++ S.Diag(getLocationOfByte(CS.getStart()), ++ diag::warn_printf_conversion_argument_type_mismatch) ++ << AT.getRepresentativeType(S.Context) << Ex->getType() ++ << getSpecifierRange(startSpecifier, specifierLen) ++ << Ex->getSourceRange(); ++ ++ // Now type check the data expression that matches the ++ // format specifier. ++ Ex = getDataArg(argIndex + 1); ++ const analyze_printf::ArgType &AT2 = ArgType::CStrTy; ++ if (AT2.isValid() && !AT2.matchesType(S.Context, Ex->getType())) ++ S.Diag(getLocationOfByte(CS.getStart()), ++ diag::warn_printf_conversion_argument_type_mismatch) ++ << AT2.getRepresentativeType(S.Context) << Ex->getType() ++ << getSpecifierRange(startSpecifier, specifierLen) ++ << Ex->getSourceRange(); ++ ++ return true; ++ } ++ // END OF FREEBSD EXTENSIONS ++ + // Check for using an Objective-C specific conversion specifier + // in a non-ObjC literal. + if (!ObjCContext && CS.isObjCArg()) { +Index: tools/clang/lib/Driver/Tools.cpp +=================================================================== +--- tools/clang/lib/Driver/Tools.cpp ++++ tools/clang/lib/Driver/Tools.cpp +@@ -2991,6 +2991,7 @@ void Clang::ConstructJob(Compilation &C, const Job + + // Forward -f (flag) options which we can pass directly. + Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); ++ Args.AddLastArg(CmdArgs, options::OPT_fformat_extensions); + Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); + Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info); + Args.AddLastArg(CmdArgs, options::OPT_fno_limit_debug_info); +Index: tools/clang/include/clang/Basic/LangOptions.def +=================================================================== +--- tools/clang/include/clang/Basic/LangOptions.def ++++ tools/clang/include/clang/Basic/LangOptions.def +@@ -84,6 +84,7 @@ LANGOPT(TraditionalCPP , 1, 0, "traditional CPP + LANGOPT(RTTI , 1, 1, "run-time type information") + LANGOPT(MSBitfields , 1, 0, "Microsoft-compatible structure layout") + LANGOPT(Freestanding, 1, 0, "freestanding implementation") ++LANGOPT(FormatExtensions , 1, 0, "FreeBSD format extensions") + LANGOPT(NoBuiltin , 1, 0, "disable builtin functions") + LANGOPT(NoMathBuiltin , 1, 0, "disable math builtin functions") + +Index: tools/clang/include/clang/Analysis/Analyses/FormatString.h +=================================================================== +--- tools/clang/include/clang/Analysis/Analyses/FormatString.h ++++ tools/clang/include/clang/Analysis/Analyses/FormatString.h +@@ -158,6 +158,11 @@ class ConversionSpecifier { + ObjCObjArg, // '@' + ObjCBeg = ObjCObjArg, ObjCEnd = ObjCObjArg, + ++ // FreeBSD specific specifiers ++ FreeBSDbArg, ++ FreeBSDDArg, ++ FreeBSDrArg, ++ + // GlibC specific specifiers. + PrintErrno, // 'm' + +Index: tools/clang/include/clang/Driver/Options.td +=================================================================== +--- tools/clang/include/clang/Driver/Options.td ++++ tools/clang/include/clang/Driver/Options.td +@@ -530,6 +530,8 @@ def fno_rewrite_includes : Flag<["-"], "fno-rewrit + + def ffreestanding : Flag<["-"], "ffreestanding">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Assert that the compilation takes place in a freestanding environment">; ++def fformat_extensions: Flag<["-"], "fformat-extensions">, Group<f_Group>, Flags<[CC1Option]>, ++ HelpText<"Enable FreeBSD kernel specific format string extensions">; + def fgnu_keywords : Flag<["-"], "fgnu-keywords">, Group<f_Group>, Flags<[CC1Option]>, + HelpText<"Allow GNU-extension keywords regardless of language standard">; + def fgnu89_inline : Flag<["-"], "fgnu89-inline">, Group<f_Group>, Flags<[CC1Option]>, diff --git a/contrib/llvm/patches/patch-r209107-clang-vendor-suffix.diff b/contrib/llvm/patches/patch-r209107-clang-vendor-suffix.diff new file mode 100644 index 0000000..d761f78 --- /dev/null +++ b/contrib/llvm/patches/patch-r209107-clang-vendor-suffix.diff @@ -0,0 +1,22 @@ +This patch adds a FreeBSD-specific suffix to clang's version string. This is +usually of the form "(yyyyddmm)", representing the date when the compiler was +last updated. + +Introduced here: http://svn.freebsd.org/changeset/base/209107 + +Index: tools/clang/lib/Basic/Version.cpp +=================================================================== +--- tools/clang/lib/Basic/Version.cpp ++++ tools/clang/lib/Basic/Version.cpp +@@ -124,8 +124,10 @@ std::string getClangFullVersion() { + OS << "clang version " CLANG_VERSION_STRING " " + << getClangFullRepositoryVersion(); + ++#ifdef CLANG_VENDOR_SUFFIX ++ OS << CLANG_VENDOR_SUFFIX; ++#elif defined(CLANG_VENDOR) + // If vendor supplied, include the base LLVM version as well. +-#ifdef CLANG_VENDOR + OS << " (based on LLVM " << PACKAGE_VERSION << ")"; + #endif + diff --git a/contrib/llvm/patches/patch-r213492-amd64-multi-os-dot.diff b/contrib/llvm/patches/patch-r213492-amd64-multi-os-dot.diff new file mode 100644 index 0000000..36bf317 --- /dev/null +++ b/contrib/llvm/patches/patch-r213492-amd64-multi-os-dot.diff @@ -0,0 +1,18 @@ +This patch makes "clang -print-multi-os-directory" print "." on amd64, which is +required by certain ports. + +Introduced here: http://svn.freebsd.org/changeset/base/213492 + +Index: tools/clang/lib/Driver/Driver.cpp +=================================================================== +--- tools/clang/lib/Driver/Driver.cpp ++++ tools/clang/lib/Driver/Driver.cpp +@@ -780,7 +780,7 @@ bool Driver::HandleImmediateArgs(const Compilation + break; + + case llvm::Triple::x86_64: +- llvm::outs() << "x86_64" << "\n"; ++ llvm::outs() << "." << "\n"; + break; + + case llvm::Triple::ppc64: diff --git a/contrib/llvm/patches/patch-r221503-default-target-triple.diff b/contrib/llvm/patches/patch-r221503-default-target-triple.diff new file mode 100644 index 0000000..d59cce9 --- /dev/null +++ b/contrib/llvm/patches/patch-r221503-default-target-triple.diff @@ -0,0 +1,26 @@ +This patch ensures the target triple that is passed during the compiler build is +respected, instead of mangling it. + +Introduced here: http://svn.freebsd.org/changeset/base/221503 + +Index: lib/Support/Unix/Host.inc +=================================================================== +--- lib/Support/Unix/Host.inc ++++ lib/Support/Unix/Host.inc +@@ -26,6 +26,11 @@ + + using namespace llvm; + ++#ifdef __FreeBSD__ ++std::string sys::getDefaultTargetTriple() { ++ return LLVM_DEFAULT_TARGET_TRIPLE; ++} ++#else // __FreeBSD__ + static std::string getOSVersion() { + struct utsname info; + +@@ -61,3 +66,4 @@ std::string sys::getDefaultTargetTriple() { + + return Triple; + } ++#endif // __FreeBSD__ diff --git a/contrib/llvm/patches/patch-r243830-arm-disable-clear-cache.diff b/contrib/llvm/patches/patch-r243830-arm-disable-clear-cache.diff new file mode 100644 index 0000000..b5a4342 --- /dev/null +++ b/contrib/llvm/patches/patch-r243830-arm-disable-clear-cache.diff @@ -0,0 +1,19 @@ +This patch ensures __clear_cache is not called on arm. In earlier versions of +clang, this special builtin was emitted as a function call, leading to link +errors. + +Introduced here: http://svn.freebsd.org/changeset/base/243830 + +Index: lib/Support/Unix/Memory.inc +=================================================================== +--- lib/Support/Unix/Memory.inc ++++ lib/Support/Unix/Memory.inc +@@ -332,7 +332,7 @@ void Memory::InvalidateInstructionCache(const void + for (intptr_t Line = StartLine; Line < EndLine; Line += LineSize) + asm volatile("icbi 0, %0" : : "r"(Line)); + asm volatile("isync"); +-# elif (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__) ++# elif (defined(__arm__) || defined(__aarch64__)) && defined(__GNUC__) && !defined(__FreeBSD__) + // FIXME: Can we safely always call this for __GNUC__ everywhere? + const char *Start = static_cast<const char *>(Addr); + const char *End = Start + Len; diff --git a/contrib/llvm/patches/patch-r252503-arm-transient-stack-alignment.diff b/contrib/llvm/patches/patch-r252503-arm-transient-stack-alignment.diff new file mode 100644 index 0000000..a046858 --- /dev/null +++ b/contrib/llvm/patches/patch-r252503-arm-transient-stack-alignment.diff @@ -0,0 +1,79 @@ +This patch applies a workaround for an ARM EABI issue, where clang would +sometimes incorrectly align the stack in a leaf function that uses TLS. + +Introduced here: http://svn.freebsd.org/changeset/base/252503 + +Index: test/CodeGen/Thumb2/large-stack.ll +=================================================================== +--- test/CodeGen/Thumb2/large-stack.ll ++++ test/CodeGen/Thumb2/large-stack.ll +@@ -13,7 +13,7 @@ define void @test1() { + define void @test2() { + ; DARWIN-LABEL: test2: + ; DARWIN: sub.w sp, sp, #4160 +-; DARWIN: sub sp, #8 ++; DARWIN: sub sp, #12 + ; LINUX-LABEL: test2: + ; LINUX: sub.w sp, sp, #4160 + ; LINUX: sub sp, #8 +Index: test/CodeGen/ARM/2009-10-30.ll +=================================================================== +--- test/CodeGen/ARM/2009-10-30.ll ++++ test/CodeGen/ARM/2009-10-30.ll +@@ -4,9 +4,10 @@ + + define void @f(i32 %a1, i32 %a2, i32 %a3, i32 %a4, i32 %a5, ...) { + entry: +-;CHECK: sub sp, sp, #4 +-;CHECK: add r{{[0-9]+}}, sp, #8 +-;CHECK: str r{{[0-9]+}}, [sp], #4 ++;CHECK: sub sp, sp, #8 ++;CHECK: add r{{[0-9]+}}, sp, #12 ++;CHECK: str r{{[0-9]+}}, [sp, #4] ++;CHECK: add sp, sp, #8 + ;CHECK: bx lr + %ap = alloca i8*, align 4 + %ap1 = bitcast i8** %ap to i8* +Index: test/CodeGen/ARM/vargs_align.ll +=================================================================== +--- test/CodeGen/ARM/vargs_align.ll ++++ test/CodeGen/ARM/vargs_align.ll +@@ -15,8 +15,8 @@ entry: + return: ; preds = %entry + %retval2 = load i32* %retval ; <i32> [#uses=1] + ret i32 %retval2 +-; EABI: add sp, sp, #12 + ; EABI: add sp, sp, #16 ++; EABI: add sp, sp, #16 ++; OABI: add sp, sp, #16 + ; OABI: add sp, sp, #12 +-; OABI: add sp, sp, #12 + } +Index: test/CodeGen/ARM/prefetch-thumb.ll +=================================================================== +--- test/CodeGen/ARM/prefetch-thumb.ll ++++ test/CodeGen/ARM/prefetch-thumb.ll +@@ -10,8 +10,8 @@ entry: + ;ARM: pld [sp, #50] + + ;THUMB2: t6: +-;THUMB2: pld [sp] +-;THUMB2: pld [sp, #50] ++;THUMB2: pld [sp, #4] ++;THUMB2: pld [sp, #54] + + %red = alloca [100 x i8], align 1 + %0 = getelementptr inbounds [100 x i8]* %red, i32 0, i32 0 +Index: lib/Target/ARM/ARMFrameLowering.h +=================================================================== +--- lib/Target/ARM/ARMFrameLowering.h ++++ lib/Target/ARM/ARMFrameLowering.h +@@ -27,7 +27,7 @@ class ARMFrameLowering : public TargetFrameLowerin + + public: + explicit ARMFrameLowering(const ARMSubtarget &sti) +- : TargetFrameLowering(StackGrowsDown, sti.getStackAlignment(), 0, 4), ++ : TargetFrameLowering(StackGrowsDown, sti.getStackAlignment(), 0, 8), + STI(sti) { + } + diff --git a/contrib/llvm/patches/patch-r257109-add-CC-aliases.diff b/contrib/llvm/patches/patch-r257109-add-CC-aliases.diff new file mode 100644 index 0000000..686210b --- /dev/null +++ b/contrib/llvm/patches/patch-r257109-add-CC-aliases.diff @@ -0,0 +1,25 @@ +This patch adds "CC" and "clang-CC" to the list of program name aliases which +invoke the C++ compiler. + +Introduced here: http://svn.freebsd.org/changeset/base/257109 + +Index: tools/clang/tools/driver/driver.cpp +=================================================================== +--- tools/clang/tools/driver/driver.cpp ++++ tools/clang/tools/driver/driver.cpp +@@ -215,6 +215,7 @@ static void ParseProgName(SmallVectorImpl<const ch + } suffixes [] = { + { "clang", 0 }, + { "clang++", "--driver-mode=g++" }, ++ { "clang-CC", "--driver-mode=g++" }, + { "clang-c++", "--driver-mode=g++" }, + { "clang-cc", 0 }, + { "clang-cpp", "--driver-mode=cpp" }, +@@ -221,6 +222,7 @@ static void ParseProgName(SmallVectorImpl<const ch + { "clang-g++", "--driver-mode=g++" }, + { "clang-gcc", 0 }, + { "clang-cl", "--driver-mode=cl" }, ++ { "CC", "--driver-mode=g++" }, + { "cc", 0 }, + { "cpp", "--driver-mode=cpp" }, + { "cl" , "--driver-mode=cl" }, diff --git a/contrib/llvm/patches/patch-r259053-gcc-installation-detector.diff b/contrib/llvm/patches/patch-r259053-gcc-installation-detector.diff new file mode 100644 index 0000000..1d04e7e --- /dev/null +++ b/contrib/llvm/patches/patch-r259053-gcc-installation-detector.diff @@ -0,0 +1,63 @@ +This patch eliminates the unnecessary search for various gcc installation +directories during each startup of clang. + +Introduced here: http://svn.freebsd.org/changeset/base/259053 + +Index: tools/clang/lib/Driver/ToolChains.cpp +=================================================================== +--- tools/clang/lib/Driver/ToolChains.cpp ++++ tools/clang/lib/Driver/ToolChains.cpp +@@ -1014,7 +1014,7 @@ static StringRef getGCCToolchainDir(const ArgList + return GCC_INSTALL_PREFIX; + } + +-/// \brief Construct a GCCInstallationDetector from the driver. ++/// \brief Initialize a GCCInstallationDetector from the driver. + /// + /// This performs all of the autodetection and sets up the various paths. + /// Once constructed, a GCCInstallationDetector is essentially immutable. +@@ -1023,9 +1023,9 @@ static StringRef getGCCToolchainDir(const ArgList + /// should instead pull the target out of the driver. This is currently + /// necessary because the driver doesn't store the final version of the target + /// triple. +-Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( +- const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args) +- : IsValid(false), D(D) { ++void ++Generic_GCC::GCCInstallationDetector::init( ++ const llvm::Triple &TargetTriple, const ArgList &Args) { + llvm::Triple BiarchVariantTriple = + TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() + : TargetTriple.get32BitArchVariant(); +@@ -1565,7 +1565,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLib + + Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple& Triple, + const ArgList &Args) +- : ToolChain(D, Triple, Args), GCCInstallation(getDriver(), Triple, Args) { ++ : ToolChain(D, Triple, Args), GCCInstallation(getDriver()) { + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); +@@ -2361,6 +2361,7 @@ static StringRef getMultilibDir(const llvm::Triple + + Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : Generic_ELF(D, Triple, Args) { ++ GCCInstallation.init(Triple, Args); + llvm::Triple::ArchType Arch = Triple.getArch(); + std::string SysRoot = computeSysRoot(); + +Index: tools/clang/lib/Driver/ToolChains.h +=================================================================== +--- tools/clang/lib/Driver/ToolChains.h ++++ tools/clang/lib/Driver/ToolChains.h +@@ -92,8 +92,8 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public + std::set<std::string> CandidateGCCInstallPaths; + + public: +- GCCInstallationDetector(const Driver &D, const llvm::Triple &TargetTriple, +- const llvm::opt::ArgList &Args); ++ GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} ++ void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); + + /// \brief Check whether we detected a valid GCC install. + bool isValid() const { return IsValid; } diff --git a/contrib/llvm/patches/patch-r259498-add-fxsave.diff b/contrib/llvm/patches/patch-r259498-add-fxsave.diff new file mode 100644 index 0000000..311be1e --- /dev/null +++ b/contrib/llvm/patches/patch-r259498-add-fxsave.diff @@ -0,0 +1,16 @@ +This patch adds the alias bit_FXSAVE for bit_FXSR to cpuid.h. + +Introduced here: http://svn.freebsd.org/changeset/base/259498 + +Index: tools/clang/lib/Headers/cpuid.h +=================================================================== +--- tools/clang/lib/Headers/cpuid.h ++++ tools/clang/lib/Headers/cpuid.h +@@ -79,6 +79,7 @@ + #define bit_ACPI 0x00400000 + #define bit_MMX 0x00800000 + #define bit_FXSR 0x01000000 ++#define bit_FXSAVE bit_FXSR /* for gcc compat */ + #define bit_SSE 0x02000000 + #define bit_SSE2 0x04000000 + #define bit_SS 0x08000000 diff --git a/contrib/llvm/patches/patch-r261680-clang-r200899-fix-security-quantis.diff b/contrib/llvm/patches/patch-r261680-clang-r200899-fix-security-quantis.diff new file mode 100644 index 0000000..be81051 --- /dev/null +++ b/contrib/llvm/patches/patch-r261680-clang-r200899-fix-security-quantis.diff @@ -0,0 +1,63 @@ +Pull in r200899 from upstream clang trunk (by Serge Pavlov): + + Allow transformation of VariableArray to ConstantArray. + + In the following code: + + struct A { static const int sz; }; + template<class T> void f() { T arr[A::sz]; } + + the array 'arr' is represented as a variable size array in the template. + If 'A::sz' gets value below in the translation unit, the array in + instantiation can turn into constant size array. + + This change fixes PR18633. + + Differential Revision: http://llvm-reviews.chandlerc.com/D2688 + +Introduced here: http://svn.freebsd.org/changeset/base/261680 + +Index: tools/clang/test/SemaCXX/c99-variable-length-array.cpp +=================================================================== +--- tools/clang/test/SemaCXX/c99-variable-length-array.cpp ++++ tools/clang/test/SemaCXX/c99-variable-length-array.cpp +@@ -140,3 +140,24 @@ namespace PR11744 { + } + int test = f<int>(0); // expected-note {{instantiation of}} + } ++ ++namespace pr18633 { ++ struct A1 { ++ static const int sz; ++ static const int sz2; ++ }; ++ const int A1::sz2 = 11; ++ template<typename T> ++ void func () { ++ int arr[A1::sz]; // expected-warning{{variable length arrays are a C99 feature}} ++ } ++ template<typename T> ++ void func2 () { ++ int arr[A1::sz2]; ++ } ++ const int A1::sz = 12; ++ void func2() { ++ func<int>(); ++ func2<int>(); ++ } ++} +Index: tools/clang/lib/Sema/TreeTransform.h +=================================================================== +--- tools/clang/lib/Sema/TreeTransform.h ++++ tools/clang/lib/Sema/TreeTransform.h +@@ -3966,7 +3966,9 @@ TreeTransform<Derived>::TransformVariableArrayType + return QualType(); + } + +- VariableArrayTypeLoc NewTL = TLB.push<VariableArrayTypeLoc>(Result); ++ // We might have constant size array now, but fortunately it has the same ++ // location layout. ++ ArrayTypeLoc NewTL = TLB.push<ArrayTypeLoc>(Result); + NewTL.setLBracketLoc(TL.getLBracketLoc()); + NewTL.setRBracketLoc(TL.getRBracketLoc()); + NewTL.setSizeExpr(Size); diff --git a/contrib/llvm/patches/patch-r261991-llvm-r195391-fix-dwarf2.diff b/contrib/llvm/patches/patch-r261991-llvm-r195391-fix-dwarf2.diff new file mode 100644 index 0000000..0a1af3e --- /dev/null +++ b/contrib/llvm/patches/patch-r261991-llvm-r195391-fix-dwarf2.diff @@ -0,0 +1,540 @@ +Pull in r195391 from upstream llvm trunk (by Eric Christopher): + + In Dwarf 3 (and Dwarf 2) attributes whose value are offsets into a + section use the form DW_FORM_data4 whilst in Dwarf 4 and later they + use the form DW_FORM_sec_offset. + + This patch updates the places where such attributes are generated to + use the appropriate form depending on the Dwarf version. The DIE entries + affected have the following tags: + DW_AT_stmt_list, DW_AT_ranges, DW_AT_location, DW_AT_GNU_pubnames, + DW_AT_GNU_pubtypes, DW_AT_GNU_addr_base, DW_AT_GNU_ranges_base + + It also adds a hidden command line option "--dwarf-version=<uint>" + to llc which allows the version of Dwarf to be generated to override + what is specified in the metadata; this makes it possible to update + existing tests to check the debugging information generated for both + Dwarf 4 (the default) and Dwarf 3 using the same metadata. + + Patch (slightly modified) by Keith Walker! + +Introduced here: http://svn.freebsd.org/changeset/base/261991 + +Index: lib/CodeGen/AsmPrinter/DIE.cpp +=================================================================== +--- lib/CodeGen/AsmPrinter/DIE.cpp ++++ lib/CodeGen/AsmPrinter/DIE.cpp +@@ -338,6 +338,7 @@ void DIEDelta::EmitValue(AsmPrinter *AP, dwarf::Fo + /// + unsigned DIEDelta::SizeOf(AsmPrinter *AP, dwarf::Form Form) const { + if (Form == dwarf::DW_FORM_data4) return 4; ++ if (Form == dwarf::DW_FORM_sec_offset) return 4; + if (Form == dwarf::DW_FORM_strp) return 4; + return AP->getDataLayout().getPointerSize(); + } +Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp +=================================================================== +--- lib/CodeGen/AsmPrinter/DwarfDebug.cpp ++++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp +@@ -105,6 +105,11 @@ DwarfPubSections("generate-dwarf-pub-sections", cl + clEnumVal(Disable, "Disabled"), clEnumValEnd), + cl::init(Default)); + ++static cl::opt<unsigned> ++DwarfVersionNumber("dwarf-version", cl::Hidden, ++ cl::desc("Generate DWARF for dwarf version."), ++ cl::init(0)); ++ + static const char *const DWARFGroupName = "DWARF Emission"; + static const char *const DbgTimerName = "DWARF Debug Writer"; + +@@ -215,7 +220,9 @@ DwarfDebug::DwarfDebug(AsmPrinter *A, Module *M) + else + HasDwarfPubSections = DwarfPubSections == Enable; + +- DwarfVersion = getDwarfVersionFromModule(MMI->getModule()); ++ DwarfVersion = DwarfVersionNumber ++ ? DwarfVersionNumber ++ : getDwarfVersionFromModule(MMI->getModule()); + + { + NamedRegionTimer T(DbgTimerName, DWARFGroupName, TimePassesIsEnabled); +@@ -470,9 +477,9 @@ DIE *DwarfDebug::constructLexicalScopeDIE(CompileU + // .debug_range section has not been laid out yet. Emit offset in + // .debug_range as a uint, size 4, for now. emitDIE will handle + // DW_AT_ranges appropriately. +- TheCU->addUInt(ScopeDIE, dwarf::DW_AT_ranges, dwarf::DW_FORM_data4, +- DebugRangeSymbols.size() +- * Asm->getDataLayout().getPointerSize()); ++ TheCU->addSectionOffset(ScopeDIE, dwarf::DW_AT_ranges, ++ DebugRangeSymbols.size() * ++ Asm->getDataLayout().getPointerSize()); + for (SmallVectorImpl<InsnRange>::const_iterator RI = Ranges.begin(), + RE = Ranges.end(); RI != RE; ++RI) { + DebugRangeSymbols.push_back(getLabelBeforeInsn(RI->first)); +@@ -525,9 +532,9 @@ DIE *DwarfDebug::constructInlinedScopeDIE(CompileU + // .debug_range section has not been laid out yet. Emit offset in + // .debug_range as a uint, size 4, for now. emitDIE will handle + // DW_AT_ranges appropriately. +- TheCU->addUInt(ScopeDIE, dwarf::DW_AT_ranges, dwarf::DW_FORM_data4, +- DebugRangeSymbols.size() +- * Asm->getDataLayout().getPointerSize()); ++ TheCU->addSectionOffset(ScopeDIE, dwarf::DW_AT_ranges, ++ DebugRangeSymbols.size() * ++ Asm->getDataLayout().getPointerSize()); + for (SmallVectorImpl<InsnRange>::const_iterator RI = Ranges.begin(), + RE = Ranges.end(); RI != RE; ++RI) { + DebugRangeSymbols.push_back(getLabelBeforeInsn(RI->first)); +@@ -758,14 +765,15 @@ CompileUnit *DwarfDebug::constructCompileUnit(DICo + // The line table entries are not always emitted in assembly, so it + // is not okay to use line_table_start here. + if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) +- NewCU->addLabel(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_sec_offset, +- UseTheFirstCU ? Asm->GetTempSymbol("section_line") +- : LineTableStartSym); ++ NewCU->addSectionLabel( ++ Die, dwarf::DW_AT_stmt_list, ++ UseTheFirstCU ? Asm->GetTempSymbol("section_line") ++ : LineTableStartSym); + else if (UseTheFirstCU) +- NewCU->addUInt(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4, 0); ++ NewCU->addSectionOffset(Die, dwarf::DW_AT_stmt_list, 0); + else +- NewCU->addDelta(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_data4, +- LineTableStartSym, DwarfLineSectionSym); ++ NewCU->addSectionDelta(Die, dwarf::DW_AT_stmt_list, ++ LineTableStartSym, DwarfLineSectionSym); + + // If we're using split dwarf the compilation dir is going to be in the + // skeleton CU and so we don't need to duplicate it here. +@@ -776,26 +784,24 @@ CompileUnit *DwarfDebug::constructCompileUnit(DICo + // emit it here if we don't have a skeleton CU for split dwarf. + if (GenerateGnuPubSections) { + if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) +- NewCU->addLabel(Die, dwarf::DW_AT_GNU_pubnames, +- dwarf::DW_FORM_sec_offset, +- Asm->GetTempSymbol("gnu_pubnames", +- NewCU->getUniqueID())); ++ NewCU->addSectionLabel( ++ Die, dwarf::DW_AT_GNU_pubnames, ++ Asm->GetTempSymbol("gnu_pubnames", NewCU->getUniqueID())); + else +- NewCU->addDelta(Die, dwarf::DW_AT_GNU_pubnames, dwarf::DW_FORM_data4, +- Asm->GetTempSymbol("gnu_pubnames", +- NewCU->getUniqueID()), +- DwarfGnuPubNamesSectionSym); ++ NewCU->addSectionDelta( ++ Die, dwarf::DW_AT_GNU_pubnames, ++ Asm->GetTempSymbol("gnu_pubnames", NewCU->getUniqueID()), ++ DwarfGnuPubNamesSectionSym); + + if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) +- NewCU->addLabel(Die, dwarf::DW_AT_GNU_pubtypes, +- dwarf::DW_FORM_sec_offset, +- Asm->GetTempSymbol("gnu_pubtypes", +- NewCU->getUniqueID())); ++ NewCU->addSectionLabel( ++ Die, dwarf::DW_AT_GNU_pubtypes, ++ Asm->GetTempSymbol("gnu_pubtypes", NewCU->getUniqueID())); + else +- NewCU->addDelta(Die, dwarf::DW_AT_GNU_pubtypes, dwarf::DW_FORM_data4, +- Asm->GetTempSymbol("gnu_pubtypes", +- NewCU->getUniqueID()), +- DwarfGnuPubTypesSectionSym); ++ NewCU->addSectionDelta( ++ Die, dwarf::DW_AT_GNU_pubtypes, ++ Asm->GetTempSymbol("gnu_pubtypes", NewCU->getUniqueID()), ++ DwarfGnuPubTypesSectionSym); + } + } + +@@ -2956,11 +2962,10 @@ CompileUnit *DwarfDebug::constructSkeletonCU(const + // Relocate to the beginning of the addr_base section, else 0 for the + // beginning of the one for this compile unit. + if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) +- NewCU->addLabel(Die, dwarf::DW_AT_GNU_addr_base, dwarf::DW_FORM_sec_offset, +- DwarfAddrSectionSym); ++ NewCU->addSectionLabel(Die, dwarf::DW_AT_GNU_addr_base, ++ DwarfAddrSectionSym); + else +- NewCU->addUInt(Die, dwarf::DW_AT_GNU_addr_base, +- dwarf::DW_FORM_sec_offset, 0); ++ NewCU->addSectionOffset(Die, dwarf::DW_AT_GNU_addr_base, 0); + + // 2.17.1 requires that we use DW_AT_low_pc for a single entry point + // into an entity. We're using 0, or a NULL label for this. +@@ -2970,10 +2975,10 @@ CompileUnit *DwarfDebug::constructSkeletonCU(const + // compile unit in debug_line section. + // FIXME: Should handle multiple compile units. + if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) +- NewCU->addLabel(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_sec_offset, +- DwarfLineSectionSym); ++ NewCU->addSectionLabel(Die, dwarf::DW_AT_stmt_list, ++ DwarfLineSectionSym); + else +- NewCU->addUInt(Die, dwarf::DW_AT_stmt_list, dwarf::DW_FORM_sec_offset, 0); ++ NewCU->addSectionOffset(Die, dwarf::DW_AT_stmt_list, 0); + + if (!CompilationDir.empty()) + NewCU->addLocalString(Die, dwarf::DW_AT_comp_dir, CompilationDir); +@@ -2981,27 +2986,31 @@ CompileUnit *DwarfDebug::constructSkeletonCU(const + // Flags to let the linker know we have emitted new style pubnames. + if (GenerateGnuPubSections) { + if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) +- NewCU->addLabel(Die, dwarf::DW_AT_GNU_pubnames, dwarf::DW_FORM_sec_offset, +- Asm->GetTempSymbol("gnu_pubnames", NewCU->getUniqueID())); ++ NewCU->addSectionLabel( ++ Die, dwarf::DW_AT_GNU_pubnames, ++ Asm->GetTempSymbol("gnu_pubnames", NewCU->getUniqueID())); + else +- NewCU->addDelta(Die, dwarf::DW_AT_GNU_pubnames, dwarf::DW_FORM_data4, +- Asm->GetTempSymbol("gnu_pubnames", NewCU->getUniqueID()), +- DwarfGnuPubNamesSectionSym); ++ NewCU->addSectionDelta( ++ Die, dwarf::DW_AT_GNU_pubnames, ++ Asm->GetTempSymbol("gnu_pubnames", NewCU->getUniqueID()), ++ DwarfGnuPubNamesSectionSym); + + if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) +- NewCU->addLabel(Die, dwarf::DW_AT_GNU_pubtypes, dwarf::DW_FORM_sec_offset, +- Asm->GetTempSymbol("gnu_pubtypes", NewCU->getUniqueID())); ++ NewCU->addSectionLabel( ++ Die, dwarf::DW_AT_GNU_pubtypes, ++ Asm->GetTempSymbol("gnu_pubtypes", NewCU->getUniqueID())); + else +- NewCU->addDelta(Die, dwarf::DW_AT_GNU_pubtypes, dwarf::DW_FORM_data4, +- Asm->GetTempSymbol("gnu_pubtypes", NewCU->getUniqueID()), +- DwarfGnuPubTypesSectionSym); ++ NewCU->addSectionDelta( ++ Die, dwarf::DW_AT_GNU_pubtypes, ++ Asm->GetTempSymbol("gnu_pubtypes", NewCU->getUniqueID()), ++ DwarfGnuPubTypesSectionSym); + } + + // Flag if we've emitted any ranges and their location for the compile unit. + if (DebugRangeSymbols.size()) { + if (Asm->MAI->doesDwarfUseRelocationsAcrossSections()) +- NewCU->addLabel(Die, dwarf::DW_AT_GNU_ranges_base, +- dwarf::DW_FORM_sec_offset, DwarfDebugRangeSectionSym); ++ NewCU->addSectionLabel(Die, dwarf::DW_AT_GNU_ranges_base, ++ DwarfDebugRangeSectionSym); + else + NewCU->addUInt(Die, dwarf::DW_AT_GNU_ranges_base, dwarf::DW_FORM_data4, + 0); +Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +=================================================================== +--- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp ++++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +@@ -227,6 +227,26 @@ void CompileUnit::addLabel(DIEBlock *Die, dwarf::F + addLabel(Die, (dwarf::Attribute)0, Form, Label); + } + ++/// addSectionLabel - Add a Dwarf section label attribute data and value. ++/// ++void CompileUnit::addSectionLabel(DIE *Die, dwarf::Attribute Attribute, ++ const MCSymbol *Label) { ++ if (DD->getDwarfVersion() >= 4) ++ addLabel(Die, Attribute, dwarf::DW_FORM_sec_offset, Label); ++ else ++ addLabel(Die, Attribute, dwarf::DW_FORM_data4, Label); ++} ++ ++/// addSectionOffset - Add an offset into a section attribute data and value. ++/// ++void CompileUnit::addSectionOffset(DIE *Die, dwarf::Attribute Attribute, ++ uint64_t Integer) { ++ if (DD->getDwarfVersion() >= 4) ++ addUInt(Die, Attribute, dwarf::DW_FORM_sec_offset, Integer); ++ else ++ addUInt(Die, Attribute, dwarf::DW_FORM_data4, Integer); ++} ++ + /// addLabelAddress - Add a dwarf label attribute data and value using + /// DW_FORM_addr or DW_FORM_GNU_addr_index. + /// +@@ -264,13 +284,15 @@ void CompileUnit::addOpAddress(DIEBlock *Die, cons + } + } + +-/// addDelta - Add a label delta attribute data and value. ++/// addSectionDelta - Add a section label delta attribute data and value. + /// +-void CompileUnit::addDelta(DIE *Die, dwarf::Attribute Attribute, +- dwarf::Form Form, const MCSymbol *Hi, +- const MCSymbol *Lo) { ++void CompileUnit::addSectionDelta(DIE *Die, dwarf::Attribute Attribute, ++ const MCSymbol *Hi, const MCSymbol *Lo) { + DIEValue *Value = new (DIEValueAllocator) DIEDelta(Hi, Lo); +- Die->addValue(Attribute, Form, Value); ++ if (DD->getDwarfVersion() >= 4) ++ Die->addValue(Attribute, dwarf::DW_FORM_sec_offset, Value); ++ else ++ Die->addValue(Attribute, dwarf::DW_FORM_data4, Value); + } + + /// addDIEEntry - Add a DIE attribute data and value. +@@ -1768,10 +1790,8 @@ DIE *CompileUnit::constructVariableDIE(DbgVariable + + unsigned Offset = DV.getDotDebugLocOffset(); + if (Offset != ~0U) { +- addLabel(VariableDie, dwarf::DW_AT_location, +- DD->getDwarfVersion() >= 4 ? dwarf::DW_FORM_sec_offset +- : dwarf::DW_FORM_data4, +- Asm->GetTempSymbol("debug_loc", Offset)); ++ addSectionLabel(VariableDie, dwarf::DW_AT_location, ++ Asm->GetTempSymbol("debug_loc", Offset)); + DV.setDIE(VariableDie); + return VariableDie; + } +Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +=================================================================== +--- lib/CodeGen/AsmPrinter/DwarfCompileUnit.h ++++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +@@ -209,6 +209,14 @@ class CompileUnit { + + void addLabel(DIEBlock *Die, dwarf::Form Form, const MCSymbol *Label); + ++ /// addSectionLabel - Add a Dwarf section label attribute data and value. ++ /// ++ void addSectionLabel(DIE *Die, dwarf::Attribute Attribute, const MCSymbol *Label); ++ ++ /// addSectionOffset - Add an offset into a section attribute data and value. ++ /// ++ void addSectionOffset(DIE *Die, dwarf::Attribute Attribute, uint64_t Integer); ++ + /// addLabelAddress - Add a dwarf label attribute data and value using + /// either DW_FORM_addr or DW_FORM_GNU_addr_index. + /// +@@ -219,10 +227,9 @@ class CompileUnit { + /// + void addOpAddress(DIEBlock *Die, const MCSymbol *Label); + +- /// addDelta - Add a label delta attribute data and value. +- /// +- void addDelta(DIE *Die, dwarf::Attribute Attribute, dwarf::Form Form, const MCSymbol *Hi, +- const MCSymbol *Lo); ++ /// addSectionDelta - Add a label delta attribute data and value. ++ void addSectionDelta(DIE *Die, dwarf::Attribute Attribute, const MCSymbol *Hi, ++ const MCSymbol *Lo); + + /// addDIEEntry - Add a DIE attribute data and value. + /// +Index: test/DebugInfo/X86/gnu-public-names.ll +=================================================================== +--- test/DebugInfo/X86/gnu-public-names.ll ++++ test/DebugInfo/X86/gnu-public-names.ll +@@ -1,5 +1,6 @@ + ; RUN: llc -mtriple=x86_64-pc-linux-gnu -generate-gnu-dwarf-pub-sections < %s | FileCheck -check-prefix=ASM %s + ; RUN: llc -mtriple=x86_64-pc-linux-gnu -generate-gnu-dwarf-pub-sections -filetype=obj < %s | llvm-dwarfdump - | FileCheck %s ++; RUN: llc -mtriple=x86_64-pc-linux-gnu -generate-gnu-dwarf-pub-sections -filetype=obj -dwarf-version=3 < %s | llvm-dwarfdump - | FileCheck %s -check-prefix=DWARF3 + ; ModuleID = 'dwarf-public-names.cpp' + ; + ; Generated from: +@@ -123,6 +124,85 @@ + ; CHECK-DAG: [[D]] EXTERNAL TYPE "ns::D" + ; CHECK-DAG: [[INT]] STATIC TYPE "int" + ++; DWARF3: .debug_info contents: ++; DWARF3: DW_AT_GNU_pubnames [DW_FORM_data4] (0x00000000) ++; DWARF3: DW_AT_GNU_pubtypes [DW_FORM_data4] (0x00000000) ++ ++; DWARF3: [[C:[0-9a-f]+]]: DW_TAG_structure_type ++; DWARF3-NEXT: DW_AT_name {{.*}} "C" ++ ++; DWARF3: [[STATIC_MEM_DECL:[0-9a-f]+]]: DW_TAG_member ++; DWARF3-NEXT: DW_AT_name {{.*}} "static_member_variable" ++ ++; DWARF3: [[MEM_FUNC_DECL:[0-9a-f]+]]: DW_TAG_subprogram ++; DWARF3-NEXT: DW_AT_MIPS_linkage_name ++; DWARF3-NEXT: DW_AT_name {{.*}} "member_function" ++ ++; DWARF3: [[STATIC_MEM_FUNC_DECL:[0-9a-f]+]]: DW_TAG_subprogram ++; DWARF3-NEXT: DW_AT_MIPS_linkage_name ++; DWARF3-NEXT: DW_AT_name {{.*}} "static_member_function" ++ ++; DWARF3: [[INT:[0-9a-f]+]]: DW_TAG_base_type ++; DWARF3-NEXT: DW_AT_name {{.*}} "int" ++ ++; DWARF3: [[STATIC_MEM_VAR:[0-9a-f]+]]: DW_TAG_variable ++; DWARF3-NEXT: DW_AT_specification {{.*}}[[STATIC_MEM_DECL]] ++ ++; DWARF3: [[GLOB_VAR:[0-9a-f]+]]: DW_TAG_variable ++; DWARF3-NEXT: DW_AT_name {{.*}} "global_variable" ++ ++; DWARF3: [[NS:[0-9a-f]+]]: DW_TAG_namespace ++; DWARF3-NEXT: DW_AT_name {{.*}} "ns" ++ ++; DWARF3: [[GLOB_NS_VAR_DECL:[0-9a-f]+]]: DW_TAG_variable ++; DWARF3-NEXT: DW_AT_name {{.*}} "global_namespace_variable" ++ ++; DWARF3: [[D_VAR_DECL:[0-9a-f]+]]: DW_TAG_variable ++; DWARF3-NEXT: DW_AT_name {{.*}} "d" ++ ++; DWARF3: [[D:[0-9a-f]+]]: DW_TAG_structure_type ++; DWARF3-NEXT: DW_AT_name {{.*}} "D" ++ ++; DWARF3: [[GLOB_NS_FUNC:[0-9a-f]+]]: DW_TAG_subprogram ++; DWARF3-NEXT: DW_AT_MIPS_linkage_name ++; DWARF3-NEXT: DW_AT_name {{.*}} "global_namespace_function" ++ ++; DWARF3: [[GLOB_NS_VAR:[0-9a-f]+]]: DW_TAG_variable ++; DWARF3-NEXT: DW_AT_specification {{.*}}[[GLOB_NS_VAR_DECL]] ++ ++; DWARF3: [[D_VAR:[0-9a-f]+]]: DW_TAG_variable ++; DWARF3-NEXT: DW_AT_specification {{.*}}[[D_VAR_DECL]] ++ ++; DWARF3: [[MEM_FUNC:[0-9a-f]+]]: DW_TAG_subprogram ++; DWARF3-NEXT: DW_AT_specification {{.*}}[[MEM_FUNC_DECL]] ++ ++; DWARF3: [[STATIC_MEM_FUNC:[0-9a-f]+]]: DW_TAG_subprogram ++; DWARF3-NEXT: DW_AT_specification {{.*}}[[STATIC_MEM_FUNC_DECL]] ++ ++; DWARF3: [[GLOBAL_FUNC:[0-9a-f]+]]: DW_TAG_subprogram ++; DWARF3-NEXT: DW_AT_MIPS_linkage_name ++; DWARF3-NEXT: DW_AT_name {{.*}} "global_function" ++ ++; DWARF3-LABEL: .debug_gnu_pubnames contents: ++; DWARF3-NEXT: length = 0x000000e7 version = 0x0002 unit_offset = 0x00000000 unit_size = 0x0000018b ++; DWARF3-NEXT: Offset Linkage Kind Name ++; DWARF3-DAG: [[GLOBAL_FUNC]] EXTERNAL FUNCTION "global_function" ++; DWARF3-DAG: [[NS]] EXTERNAL TYPE "ns" ++; DWARF3-DAG: [[MEM_FUNC]] EXTERNAL FUNCTION "C::member_function" ++; DWARF3-DAG: [[GLOB_VAR]] EXTERNAL VARIABLE "global_variable" ++; DWARF3-DAG: [[GLOB_NS_VAR]] EXTERNAL VARIABLE "ns::global_namespace_variable" ++; DWARF3-DAG: [[GLOB_NS_FUNC]] EXTERNAL FUNCTION "ns::global_namespace_function" ++; DWARF3-DAG: [[D_VAR]] EXTERNAL VARIABLE "ns::d" ++; DWARF3-DAG: [[STATIC_MEM_VAR]] EXTERNAL VARIABLE "C::static_member_variable" ++; DWARF3-DAG: [[STATIC_MEM_FUNC]] EXTERNAL FUNCTION "C::static_member_function" ++ ++ ++; DWARF3-LABEL: debug_gnu_pubtypes contents: ++; DWARF3: Offset Linkage Kind Name ++; DWARF3-DAG: [[C]] EXTERNAL TYPE "C" ++; DWARF3-DAG: [[D]] EXTERNAL TYPE "ns::D" ++; DWARF3-DAG: [[INT]] STATIC TYPE "int" ++ + %struct.C = type { i8 } + %"struct.ns::D" = type { i32 } + +Index: test/DebugInfo/X86/stmt-list-multiple-compile-units.ll +=================================================================== +--- test/DebugInfo/X86/stmt-list-multiple-compile-units.ll ++++ test/DebugInfo/X86/stmt-list-multiple-compile-units.ll +@@ -1,5 +1,7 @@ + ; RUN: llc -O0 %s -mtriple=x86_64-apple-darwin -filetype=obj -o %t + ; RUN: llvm-dwarfdump %t | FileCheck %s ++; RUN: llc -O0 %s -mtriple=x86_64-apple-darwin -filetype=obj -o %t -dwarf-version=3 ++; RUN: llvm-dwarfdump %t | FileCheck %s -check-prefix=DWARF3 + ; RUN: llc < %s -O0 -mtriple=x86_64-apple-macosx10.7 | FileCheck %s -check-prefix=ASM + + ; rdar://13067005 +@@ -6,11 +8,11 @@ + ; CHECK: .debug_info contents: + ; CHECK: DW_TAG_compile_unit + ; CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +-; CHECK: DW_AT_stmt_list [DW_FORM_data4] (0x00000000) ++; CHECK: DW_AT_stmt_list [DW_FORM_sec_offset] (0x00000000) + + ; CHECK: DW_TAG_compile_unit + ; CHECK: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) +-; CHECK: DW_AT_stmt_list [DW_FORM_data4] (0x0000003c) ++; CHECK: DW_AT_stmt_list [DW_FORM_sec_offset] (0x0000003c) + + ; CHECK: .debug_line contents: + ; CHECK-NEXT: Line table prologue: +@@ -21,6 +23,24 @@ + ; CHECK: file_names[ 1] 0 0x00000000 0x00000000 simple2.c + ; CHECK-NOT: file_names + ++; DWARF3: .debug_info contents: ++; DWARF3: DW_TAG_compile_unit ++; DWARF3: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) ++; DWARF3: DW_AT_stmt_list [DW_FORM_data4] (0x00000000) ++ ++; DWARF3: DW_TAG_compile_unit ++; DWARF3: DW_AT_low_pc [DW_FORM_addr] (0x0000000000000000) ++; DWARF3: DW_AT_stmt_list [DW_FORM_data4] (0x0000003c) ++ ++; DWARF3: .debug_line contents: ++; DWARF3-NEXT: Line table prologue: ++; DWARF3-NEXT: total_length: 0x00000038 ++; DWARF3: file_names[ 1] 0 0x00000000 0x00000000 simple.c ++; DWARF3: Line table prologue: ++; DWARF3-NEXT: total_length: 0x00000039 ++; DWARF3: file_names[ 1] 0 0x00000000 0x00000000 simple2.c ++; DWARF3-NOT: file_names ++ + ; PR15408 + ; ASM: L__DWARF__debug_info_begin0: + ; ASM: .long 0 ## DW_AT_stmt_list +Index: test/DebugInfo/X86/block-capture.ll +=================================================================== +--- test/DebugInfo/X86/block-capture.ll ++++ test/DebugInfo/X86/block-capture.ll +@@ -1,5 +1,7 @@ + ; RUN: llc -mtriple=x86_64-apple-darwin %s -o %t -filetype=obj + ; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s ++; RUN: llc -mtriple=x86_64-apple-darwin %s -o %t -filetype=obj -dwarf-version=3 ++; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s -check-prefix=DWARF3 + + ; Checks that we emit debug info for the block variable declare. + ; CHECK: DW_TAG_subprogram [3] +@@ -7,6 +9,11 @@ + ; CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[{{.*}}] = "block") + ; CHECK: DW_AT_location [DW_FORM_sec_offset] ({{.*}}) + ++; DWARF3: DW_TAG_subprogram [3] ++; DWARF3: DW_TAG_variable [5] ++; DWARF3: DW_AT_name [DW_FORM_strp] ( .debug_str[{{.*}}] = "block") ++; DWARF3: DW_AT_location [DW_FORM_data4] ({{.*}}) ++ + %struct.__block_descriptor = type { i64, i64 } + %struct.__block_literal_generic = type { i8*, i32, i32, i8*, %struct.__block_descriptor* } + +Index: test/DebugInfo/X86/op_deref.ll +=================================================================== +--- test/DebugInfo/X86/op_deref.ll ++++ test/DebugInfo/X86/op_deref.ll +@@ -1,5 +1,7 @@ + ; RUN: llc -O0 -mtriple=x86_64-apple-darwin %s -o %t -filetype=obj + ; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s -check-prefix=DW-CHECK ++; RUN: llc -O0 -mtriple=x86_64-apple-darwin %s -o %t -filetype=obj -dwarf-version=3 ++; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s -check-prefix=DWARF3 + + ; DW-CHECK: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000067] = "vla") + ; FIXME: The location here needs to be fixed, but llvm-dwarfdump doesn't handle +@@ -6,6 +8,11 @@ + ; DW_AT_location lists yet. + ; DW-CHECK: DW_AT_location [DW_FORM_sec_offset] (0x00000000) + ++; DWARF3: DW_AT_name [DW_FORM_strp] ( .debug_str[0x00000067] = "vla") ++; FIXME: The location here needs to be fixed, but llvm-dwarfdump doesn't handle ++; DW_AT_location lists yet. ++; DWARF3: DW_AT_location [DW_FORM_data4] (0x00000000) ++ + ; Unfortunately llvm-dwarfdump can't unparse a list of DW_AT_locations + ; right now, so we check the asm output: + ; RUN: llc -O0 -mtriple=x86_64-apple-darwin %s -o - -filetype=asm | FileCheck %s -check-prefix=ASM-CHECK +Index: test/DebugInfo/X86/DW_AT_stmt_list_sec_offset.ll +=================================================================== +--- test/DebugInfo/X86/DW_AT_stmt_list_sec_offset.ll ++++ test/DebugInfo/X86/DW_AT_stmt_list_sec_offset.ll +@@ -1,7 +1,10 @@ + ; RUN: llc -mtriple=i686-w64-mingw32 -o %t -filetype=obj %s + ; RUN: llvm-dwarfdump -debug-dump=all %t | FileCheck %s ++; RUN: llc -mtriple=i686-w64-mingw32 -o %t -filetype=obj -dwarf-version=3 %s ++; RUN: llvm-dwarfdump -debug-dump=all %t | FileCheck %s -check-prefix=DWARF3 + + ; CHECK: DW_AT_stmt_list [DW_FORM_sec_offset] ++; DWARF3: DW_AT_stmt_list [DW_FORM_data4] + ; + ; generated from: + ; clang -g -S -emit-llvm test.c -o test.ll +@@ -36,6 +39,6 @@ attributes #0 = { nounwind "less-precise-fpmad"="f + !6 = metadata !{i32 786453, i32 0, null, metadata !"", i32 0, i64 0, i64 0, i64 0, i32 0, null, metadata !7, i32 0, null, null, null} ; [ DW_TAG_subroutine_type ] [line 0, size 0, align 0, offset 0] [from ] + !7 = metadata !{metadata !8} + !8 = metadata !{i32 786468, null, null, metadata !"int", i32 0, i64 32, i64 32, i64 0, i32 0, i32 5} ; [ DW_TAG_base_type ] [int] [line 0, size 32, align 32, offset 0, enc DW_ATE_signed] +-!9 = metadata !{i32 2, metadata !"Dwarf Version", i32 3} ++!9 = metadata !{i32 2, metadata !"Dwarf Version", i32 4} + !10 = metadata !{i32 3, i32 0, metadata !4, null} + !11 = metadata !{i32 1, metadata !"Debug Info Version", i32 1} diff --git a/contrib/llvm/patches/patch-r261991-llvm-r198385-fix-dwarf2.diff b/contrib/llvm/patches/patch-r261991-llvm-r198385-fix-dwarf2.diff new file mode 100644 index 0000000..375f662 --- /dev/null +++ b/contrib/llvm/patches/patch-r261991-llvm-r198385-fix-dwarf2.diff @@ -0,0 +1,91 @@ +Pull in r198385 from upstream llvm trunk (by David Blaikie): + + Reverting r193835 due to weirdness with Go... + + Apologies for the noise - we're seeing some Go failures with cgo + interacting with Clang's debug info due to this change. + +Introduced here: http://svn.freebsd.org/changeset/base/261991 + +Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +=================================================================== +--- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp ++++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +@@ -1845,9 +1845,6 @@ void CompileUnit::constructMemberDIE(DIE &Buffer, + + addSourceLine(MemberDie, DT); + +- DIEBlock *MemLocationDie = new (DIEValueAllocator) DIEBlock(); +- addUInt(MemLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); +- + if (DT.getTag() == dwarf::DW_TAG_inheritance && DT.isVirtual()) { + + // For C++, virtual base classes are not at fixed offset. Use following +@@ -1892,7 +1889,11 @@ void CompileUnit::constructMemberDIE(DIE &Buffer, + } else + // This is not a bitfield. + OffsetInBytes = DT.getOffsetInBits() >> 3; +- addUInt(MemberDie, dwarf::DW_AT_data_member_location, None, OffsetInBytes); ++ ++ DIEBlock *MemLocationDie = new (DIEValueAllocator) DIEBlock(); ++ addUInt(MemLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); ++ addUInt(MemLocationDie, dwarf::DW_FORM_udata, OffsetInBytes); ++ addBlock(MemberDie, dwarf::DW_AT_data_member_location, MemLocationDie); + } + + if (DT.isProtected()) +Index: test/DebugInfo/X86/data_member_location.ll +=================================================================== +--- test/DebugInfo/X86/data_member_location.ll ++++ test/DebugInfo/X86/data_member_location.ll +@@ -11,11 +11,11 @@ + + ; CHECK: DW_AT_name {{.*}} "c" + ; CHECK-NOT: DW_TAG +-; CHECK: DW_AT_data_member_location {{.*}} (0x00) ++; CHECK: DW_AT_data_member_location {{.*}} (<0x02> 23 00 ) + + ; CHECK: DW_AT_name {{.*}} "i" + ; CHECK-NOT: DW_TAG +-; CHECK: DW_AT_data_member_location {{.*}} (0x04) ++; CHECK: DW_AT_data_member_location {{.*}} (<0x02> 23 04 ) + + %struct.foo = type { i8, i32 } + +Index: test/DebugInfo/X86/concrete_out_of_line.ll +=================================================================== +--- test/DebugInfo/X86/concrete_out_of_line.ll ++++ test/DebugInfo/X86/concrete_out_of_line.ll +@@ -7,7 +7,7 @@ + ; first check that we have a TAG_subprogram at a given offset and it has + ; AT_inline. + +-; CHECK: 0x0000011c: DW_TAG_subprogram [17] ++; CHECK: 0x0000011e: DW_TAG_subprogram [17] + ; CHECK-NEXT: DW_AT_specification + ; CHECK-NEXT: DW_AT_inline + +@@ -14,8 +14,8 @@ + + ; and then that a TAG_subprogram refers to it with AT_abstract_origin. + +-; CHECK: 0x0000015d: DW_TAG_subprogram [19] +-; CHECK-NEXT: DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x011c => {0x0000011c}) ++; CHECK: 0x0000015f: DW_TAG_subprogram [19] ++; CHECK-NEXT: DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x011e => {0x0000011e}) + + define i32 @_ZN17nsAutoRefCnt7ReleaseEv() { + entry: +Index: test/DebugInfo/X86/generate-odr-hash.ll +=================================================================== +--- test/DebugInfo/X86/generate-odr-hash.ll ++++ test/DebugInfo/X86/generate-odr-hash.ll +@@ -1,5 +1,8 @@ + ; REQUIRES: object-emission + ++; Fail while investigating problem with non-block representations of member offsets. ++; XFAIL: * ++ + ; RUN: llc %s -o %t -filetype=obj -O0 -generate-odr-hash -mtriple=x86_64-unknown-linux-gnu + ; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s + ; diff --git a/contrib/llvm/patches/patch-r261991-llvm-r198389-fix-dwarf2.diff b/contrib/llvm/patches/patch-r261991-llvm-r198389-fix-dwarf2.diff new file mode 100644 index 0000000..a4a00a9 --- /dev/null +++ b/contrib/llvm/patches/patch-r261991-llvm-r198389-fix-dwarf2.diff @@ -0,0 +1,105 @@ +Pull in r198389 from upstream llvm trunk (by David Blaikie): + + Revert "Reverting r193835 due to weirdness with Go..." + + The cgo problem was that it wants dwarf2 which doesn't support direct + constant encoding of the location. So let's add support for dwarf2 + encoding (using a location expression) of data member locations. + + This reverts commit r198385. + +Introduced here: http://svn.freebsd.org/changeset/base/261991 + +Index: lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +=================================================================== +--- lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp ++++ lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +@@ -1890,10 +1890,14 @@ void CompileUnit::constructMemberDIE(DIE &Buffer, + // This is not a bitfield. + OffsetInBytes = DT.getOffsetInBits() >> 3; + +- DIEBlock *MemLocationDie = new (DIEValueAllocator) DIEBlock(); +- addUInt(MemLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); +- addUInt(MemLocationDie, dwarf::DW_FORM_udata, OffsetInBytes); +- addBlock(MemberDie, dwarf::DW_AT_data_member_location, MemLocationDie); ++ if (DD->getDwarfVersion() <= 2) { ++ DIEBlock *MemLocationDie = new (DIEValueAllocator) DIEBlock(); ++ addUInt(MemLocationDie, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst); ++ addUInt(MemLocationDie, dwarf::DW_FORM_udata, OffsetInBytes); ++ addBlock(MemberDie, dwarf::DW_AT_data_member_location, MemLocationDie); ++ } else ++ addUInt(MemberDie, dwarf::DW_AT_data_member_location, None, ++ OffsetInBytes); + } + + if (DT.isProtected()) +Index: test/DebugInfo/X86/data_member_location.ll +=================================================================== +--- test/DebugInfo/X86/data_member_location.ll ++++ test/DebugInfo/X86/data_member_location.ll +@@ -1,4 +1,5 @@ + ; RUN: llc -mtriple=x86_64-linux -O0 -o - -filetype=obj < %s | llvm-dwarfdump -debug-dump=info -| FileCheck %s ++; RUN: llc -mtriple=x86_64-linux -dwarf-version=2 -O0 -o - -filetype=obj < %s | llvm-dwarfdump -debug-dump=info -| FileCheck -check-prefix=DWARF2 %s + + ; Generated from Clang with the following source: + ; +@@ -11,12 +12,20 @@ + + ; CHECK: DW_AT_name {{.*}} "c" + ; CHECK-NOT: DW_TAG +-; CHECK: DW_AT_data_member_location {{.*}} (<0x02> 23 00 ) ++; CHECK: DW_AT_data_member_location {{.*}} (0x00) + + ; CHECK: DW_AT_name {{.*}} "i" + ; CHECK-NOT: DW_TAG +-; CHECK: DW_AT_data_member_location {{.*}} (<0x02> 23 04 ) ++; CHECK: DW_AT_data_member_location {{.*}} (0x04) + ++; DWARF2: DW_AT_name {{.*}} "c" ++; DWARF2-NOT: DW_TAG ++; DWARF2: DW_AT_data_member_location {{.*}} (<0x02> 23 00 ) ++ ++; DWARF2: DW_AT_name {{.*}} "i" ++; DWARF2-NOT: DW_TAG ++; DWARF2: DW_AT_data_member_location {{.*}} (<0x02> 23 04 ) ++ + %struct.foo = type { i8, i32 } + + @f = global %struct.foo zeroinitializer, align 4 +Index: test/DebugInfo/X86/concrete_out_of_line.ll +=================================================================== +--- test/DebugInfo/X86/concrete_out_of_line.ll ++++ test/DebugInfo/X86/concrete_out_of_line.ll +@@ -7,7 +7,7 @@ + ; first check that we have a TAG_subprogram at a given offset and it has + ; AT_inline. + +-; CHECK: 0x0000011e: DW_TAG_subprogram [17] ++; CHECK: 0x0000011c: DW_TAG_subprogram [17] + ; CHECK-NEXT: DW_AT_specification + ; CHECK-NEXT: DW_AT_inline + +@@ -14,8 +14,8 @@ + + ; and then that a TAG_subprogram refers to it with AT_abstract_origin. + +-; CHECK: 0x0000015f: DW_TAG_subprogram [19] +-; CHECK-NEXT: DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x011e => {0x0000011e}) ++; CHECK: 0x0000015d: DW_TAG_subprogram [19] ++; CHECK-NEXT: DW_AT_abstract_origin [DW_FORM_ref4] (cu + 0x011c => {0x0000011c}) + + define i32 @_ZN17nsAutoRefCnt7ReleaseEv() { + entry: +Index: test/DebugInfo/X86/generate-odr-hash.ll +=================================================================== +--- test/DebugInfo/X86/generate-odr-hash.ll ++++ test/DebugInfo/X86/generate-odr-hash.ll +@@ -1,8 +1,5 @@ + ; REQUIRES: object-emission + +-; Fail while investigating problem with non-block representations of member offsets. +-; XFAIL: * +- + ; RUN: llc %s -o %t -filetype=obj -O0 -generate-odr-hash -mtriple=x86_64-unknown-linux-gnu + ; RUN: llvm-dwarfdump -debug-dump=info %t | FileCheck %s + ; diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198028-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198028-sparc.diff new file mode 100644 index 0000000..b4fb929 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198028-sparc.diff @@ -0,0 +1,258 @@ +Pull in r198028 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add MCInstPrinter implementation for SPARC. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/InstPrinter/LLVMBuild.txt +=================================================================== +--- lib/Target/Sparc/InstPrinter/LLVMBuild.txt ++++ lib/Target/Sparc/InstPrinter/LLVMBuild.txt +@@ -0,0 +1,23 @@ ++;===- ./lib/Target/Sparc/InstPrinter/LLVMBuild.txt -------------*- Conf -*--===; ++; ++; The LLVM Compiler Infrastructure ++; ++; This file is distributed under the University of Illinois Open Source ++; License. See LICENSE.TXT for details. ++; ++;===------------------------------------------------------------------------===; ++; ++; This is an LLVMBuild description file for the components in this subdirectory. ++; ++; For more information on the LLVMBuild system, please see: ++; ++; http://llvm.org/docs/LLVMBuild.html ++; ++;===------------------------------------------------------------------------===; ++ ++[component_0] ++type = Library ++name = SparcAsmPrinter ++parent = Sparc ++required_libraries = MC Support ++add_to_library_groups = Sparc +Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp +=================================================================== +--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp ++++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp +@@ -0,0 +1,95 @@ ++//===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly syntax -----==// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++// ++// This class prints an Sparc MCInst to a .s file. ++// ++//===----------------------------------------------------------------------===// ++ ++#define DEBUG_TYPE "asm-printer" ++#include "SparcInstPrinter.h" ++ ++#include "Sparc.h" ++#include "MCTargetDesc/SparcBaseInfo.h" ++#include "llvm/MC/MCExpr.h" ++#include "llvm/MC/MCInst.h" ++#include "llvm/MC/MCSymbol.h" ++#include "llvm/Support/raw_ostream.h" ++using namespace llvm; ++ ++#define GET_INSTRUCTION_NAME ++// Uncomment the following line once we are ready to use MCAsmWriter. ++//#include "SparcGenAsmWriter.inc" ++ ++void SparcInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const ++{ ++ OS << '%' << StringRef(getRegisterName(RegNo)).lower(); ++} ++ ++void SparcInstPrinter::printInst(const MCInst *MI, raw_ostream &O, ++ StringRef Annot) ++{ ++ printInstruction(MI, O); ++ printAnnotation(O, Annot); ++} ++ ++void SparcInstPrinter::printOperand(const MCInst *MI, int opNum, ++ raw_ostream &O) ++{ ++ const MCOperand &MO = MI->getOperand (opNum); ++ ++ if (MO.isReg()) { ++ printRegName(O, MO.getReg()); ++ return ; ++ } ++ ++ if (MO.isImm()) { ++ O << (int)MO.getImm(); ++ return; ++ } ++ ++ assert(MO.isExpr() && "Unknown operand kind in printOperand"); ++ MO.getExpr()->print(O); ++} ++ ++void SparcInstPrinter::printMemOperand(const MCInst *MI, int opNum, ++ raw_ostream &O, const char *Modifier) ++{ ++ printOperand(MI, opNum, O); ++ ++ // If this is an ADD operand, emit it like normal operands. ++ if (Modifier && !strcmp(Modifier, "arith")) { ++ O << ", "; ++ printOperand(MI, opNum+1, O); ++ return; ++ } ++ const MCOperand &MO = MI->getOperand(opNum+1); ++ ++ if (MO.isReg() && MO.getReg() == SP::G0) ++ return; // don't print "+%g0" ++ if (MO.isImm() && MO.getImm() == 0) ++ return; // don't print "+0" ++ ++ O << "+"; ++ ++ printOperand(MI, opNum+1, O); ++} ++ ++void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum, ++ raw_ostream &O) ++{ ++ int CC = (int)MI->getOperand(opNum).getImm(); ++ O << SPARCCondCodeToString((SPCC::CondCodes)CC); ++} ++ ++bool SparcInstPrinter::printGetPCX(const MCInst *MI, unsigned opNum, ++ raw_ostream &O) ++{ ++ assert(0 && "FIXME: Implement SparcInstPrinter::printGetPCX."); ++ return true; ++} +Index: lib/Target/Sparc/InstPrinter/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/InstPrinter/CMakeLists.txt ++++ lib/Target/Sparc/InstPrinter/CMakeLists.txt +@@ -0,0 +1,3 @@ ++add_llvm_library(LLVMSparcAsmPrinter ++ SparcInstPrinter.cpp ++ ) +Index: lib/Target/Sparc/InstPrinter/Makefile +=================================================================== +--- lib/Target/Sparc/InstPrinter/Makefile ++++ lib/Target/Sparc/InstPrinter/Makefile +@@ -0,0 +1,16 @@ ++##===- lib/Target/Sparc/InstPrinter/Makefile ---------------*- Makefile -*-===## ++# ++# The LLVM Compiler Infrastructure ++# ++# This file is distributed under the University of Illinois Open Source ++# License. See LICENSE.TXT for details. ++# ++##===----------------------------------------------------------------------===## ++ ++LEVEL = ../../../.. ++LIBRARYNAME = LLVMSparcAsmPrinter ++ ++# Hack: we need to include 'main' target directory to grab private headers ++CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. ++ ++include $(LEVEL)/Makefile.common +Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.h +=================================================================== +--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.h ++++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.h +@@ -0,0 +1,46 @@ ++//===-- SparcInstPrinter.h - Convert Sparc MCInst to assembly syntax ------===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++// ++// This class prints an Sparc MCInst to a .s file. ++// ++//===----------------------------------------------------------------------===// ++ ++#ifndef SparcINSTPRINTER_H ++#define SparcINSTPRINTER_H ++ ++#include "llvm/MC/MCInstPrinter.h" ++ ++namespace llvm { ++ ++class MCOperand; ++ ++class SparcInstPrinter : public MCInstPrinter { ++public: ++ SparcInstPrinter(const MCAsmInfo &MAI, ++ const MCInstrInfo &MII, ++ const MCRegisterInfo &MRI) ++ : MCInstPrinter(MAI, MII, MRI) {} ++ ++ virtual void printRegName(raw_ostream &OS, unsigned RegNo) const; ++ virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot); ++ ++ // Autogenerated by tblgen. ++ void printInstruction(const MCInst *MI, raw_ostream &O); ++ static const char *getRegisterName(unsigned RegNo); ++ ++ void printOperand(const MCInst *MI, int opNum, raw_ostream &OS); ++ void printMemOperand(const MCInst *MI, int opNum, raw_ostream &OS, ++ const char *Modifier = 0); ++ void printCCOperand(const MCInst *MI, int opNum, raw_ostream &OS); ++ bool printGetPCX(const MCInst *MI, unsigned OpNo, raw_ostream &OS); ++ ++}; ++} // end namespace llvm ++ ++#endif +Index: lib/Target/Sparc/LLVMBuild.txt +=================================================================== +--- lib/Target/Sparc/LLVMBuild.txt ++++ lib/Target/Sparc/LLVMBuild.txt +@@ -16,7 +16,7 @@ + ;===------------------------------------------------------------------------===; + + [common] +-subdirectories = MCTargetDesc TargetInfo ++subdirectories = InstPrinter MCTargetDesc TargetInfo + + [component_0] + type = TargetGroup +@@ -29,6 +29,6 @@ has_jit = 1 + type = Library + name = SparcCodeGen + parent = Sparc +-required_libraries = AsmPrinter CodeGen Core MC SelectionDAG SparcDesc +- SparcInfo Support Target ++required_libraries = AsmPrinter CodeGen Core MC SelectionDAG SparcAsmPrinter ++ SparcDesc SparcInfo Support Target + add_to_library_groups = Sparc +Index: lib/Target/Sparc/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/CMakeLists.txt ++++ lib/Target/Sparc/CMakeLists.txt +@@ -29,3 +29,4 @@ add_dependencies(LLVMSparcCodeGen SparcCommonTable + + add_subdirectory(TargetInfo) + add_subdirectory(MCTargetDesc) ++add_subdirectory(InstPrinter) +Index: lib/Target/Sparc/Makefile +=================================================================== +--- lib/Target/Sparc/Makefile ++++ lib/Target/Sparc/Makefile +@@ -17,7 +17,7 @@ BUILT_SOURCES = SparcGenRegisterInfo.inc SparcGenI + SparcGenSubtargetInfo.inc SparcGenCallingConv.inc \ + SparcGenCodeEmitter.inc + +-DIRS = TargetInfo MCTargetDesc ++DIRS = InstPrinter TargetInfo MCTargetDesc + + include $(LEVEL)/Makefile.common + diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198029-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198029-sparc.diff new file mode 100644 index 0000000..6656bce --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198029-sparc.diff @@ -0,0 +1,210 @@ +Pull in r198029 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add target specific MCExpr class to handle sparc specific modifiers like %hi, %lo, etc., + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +@@ -0,0 +1,84 @@ ++//===-- SparcMCExpr.cpp - Sparc specific MC expression classes --------===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++// ++// This file contains the implementation of the assembly expression modifiers ++// accepted by the Sparc architecture (e.g. "%hi", "%lo", ...). ++// ++//===----------------------------------------------------------------------===// ++ ++#define DEBUG_TYPE "sparcmcexpr" ++#include "SparcMCExpr.h" ++#include "llvm/MC/MCContext.h" ++#include "llvm/MC/MCAssembler.h" ++#include "llvm/MC/MCELF.h" ++#include "llvm/Object/ELF.h" ++ ++ ++using namespace llvm; ++ ++const SparcMCExpr* ++SparcMCExpr::Create(VariantKind Kind, const MCExpr *Expr, ++ MCContext &Ctx) { ++ return new (Ctx) SparcMCExpr(Kind, Expr); ++} ++ ++ ++void SparcMCExpr::PrintImpl(raw_ostream &OS) const ++{ ++ bool closeParen = true; ++ switch (Kind) { ++ case VK_Sparc_None: closeParen = false; break; ++ case VK_Sparc_LO: OS << "%lo("; break; ++ case VK_Sparc_HI: OS << "%hi("; break; ++ case VK_Sparc_H44: OS << "%h44("; break; ++ case VK_Sparc_M44: OS << "%m44("; break; ++ case VK_Sparc_L44: OS << "%l44("; break; ++ case VK_Sparc_HH: OS << "%hh("; break; ++ case VK_Sparc_HM: OS << "%hm("; break; ++ case VK_Sparc_TLS_GD_HI22: OS << "%tgd_hi22("; break; ++ case VK_Sparc_TLS_GD_LO10: OS << "%tgd_lo10("; break; ++ case VK_Sparc_TLS_GD_ADD: OS << "%tgd_add("; break; ++ case VK_Sparc_TLS_GD_CALL: OS << "%tgd_call("; break; ++ case VK_Sparc_TLS_LDM_HI22: OS << "%tldm_hi22("; break; ++ case VK_Sparc_TLS_LDM_LO10: OS << "%tldm_lo10("; break; ++ case VK_Sparc_TLS_LDM_ADD: OS << "%tldm_add("; break; ++ case VK_Sparc_TLS_LDM_CALL: OS << "%tldm_call("; break; ++ case VK_Sparc_TLS_LDO_HIX22: OS << "%tldo_hix22("; break; ++ case VK_Sparc_TLS_LDO_LOX10: OS << "%tldo_lox10("; break; ++ case VK_Sparc_TLS_LDO_ADD: OS << "%tldo_add("; break; ++ case VK_Sparc_TLS_IE_HI22: OS << "%tie_hi22("; break; ++ case VK_Sparc_TLS_IE_LO10: OS << "%tie_lo10("; break; ++ case VK_Sparc_TLS_IE_LD: OS << "%tie_ld("; break; ++ case VK_Sparc_TLS_IE_LDX: OS << "%tie_ldx("; break; ++ case VK_Sparc_TLS_IE_ADD: OS << "%tie_add("; break; ++ case VK_Sparc_TLS_LE_HIX22: OS << "%tle_hix22("; break; ++ case VK_Sparc_TLS_LE_LOX10: OS << "%tle_lox10("; break; ++ } ++ ++ const MCExpr *Expr = getSubExpr(); ++ Expr->print(OS); ++ if (closeParen) ++ OS << ')'; ++} ++ ++bool ++SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Res, ++ const MCAsmLayout *Layout) const { ++ assert(0 && "FIXME: Implement SparcMCExpr::EvaluateAsRelocatableImpl"); ++ return getSubExpr()->EvaluateAsRelocatable(Res, *Layout); ++} ++ ++ ++void SparcMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { ++ assert(0 && "FIXME: Implement SparcMCExpr::fixELFSymbolsInTLSFixups"); ++} ++ ++void SparcMCExpr::AddValueSymbols(MCAssembler *Asm) const { ++ assert(0 && "FIXME: Implement SparcMCExpr::AddValueSymbols"); ++} +Index: lib/Target/Sparc/MCTargetDesc/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/CMakeLists.txt ++++ lib/Target/Sparc/MCTargetDesc/CMakeLists.txt +@@ -1,6 +1,7 @@ + add_llvm_library(LLVMSparcDesc + SparcMCTargetDesc.cpp + SparcMCAsmInfo.cpp ++ SparcMCExpr.cpp + ) + + add_dependencies(LLVMSparcDesc SparcCommonTableGen) +Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h ++++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h +@@ -0,0 +1,98 @@ ++//====- SparcMCExpr.h - Sparc specific MC expression classes --*- C++ -*-=====// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++// ++// This file describes Sparc-specific MCExprs, used for modifiers like ++// "%hi" or "%lo" etc., ++// ++//===----------------------------------------------------------------------===// ++ ++#ifndef LLVM_SPARCMCEXPR_H ++#define LLVM_SPARCMCEXPR_H ++ ++#include "llvm/MC/MCExpr.h" ++ ++namespace llvm { ++ ++class SparcMCExpr : public MCTargetExpr { ++public: ++ enum VariantKind { ++ VK_Sparc_None, ++ VK_Sparc_LO, ++ VK_Sparc_HI, ++ VK_Sparc_H44, ++ VK_Sparc_M44, ++ VK_Sparc_L44, ++ VK_Sparc_HH, ++ VK_Sparc_HM, ++ VK_Sparc_TLS_GD_HI22, ++ VK_Sparc_TLS_GD_LO10, ++ VK_Sparc_TLS_GD_ADD, ++ VK_Sparc_TLS_GD_CALL, ++ VK_Sparc_TLS_LDM_HI22, ++ VK_Sparc_TLS_LDM_LO10, ++ VK_Sparc_TLS_LDM_ADD, ++ VK_Sparc_TLS_LDM_CALL, ++ VK_Sparc_TLS_LDO_HIX22, ++ VK_Sparc_TLS_LDO_LOX10, ++ VK_Sparc_TLS_LDO_ADD, ++ VK_Sparc_TLS_IE_HI22, ++ VK_Sparc_TLS_IE_LO10, ++ VK_Sparc_TLS_IE_LD, ++ VK_Sparc_TLS_IE_LDX, ++ VK_Sparc_TLS_IE_ADD, ++ VK_Sparc_TLS_LE_HIX22, ++ VK_Sparc_TLS_LE_LOX10 ++ }; ++ ++private: ++ const VariantKind Kind; ++ const MCExpr *Expr; ++ ++ explicit SparcMCExpr(VariantKind _Kind, const MCExpr *_Expr) ++ : Kind(_Kind), Expr(_Expr) {} ++ ++public: ++ /// @name Construction ++ /// @{ ++ ++ static const SparcMCExpr *Create(VariantKind Kind, const MCExpr *Expr, ++ MCContext &Ctx); ++ /// @} ++ /// @name Accessors ++ /// @{ ++ ++ /// getOpcode - Get the kind of this expression. ++ VariantKind getKind() const { return Kind; } ++ ++ /// getSubExpr - Get the child of this expression. ++ const MCExpr *getSubExpr() const { return Expr; } ++ ++ /// @} ++ void PrintImpl(raw_ostream &OS) const; ++ bool EvaluateAsRelocatableImpl(MCValue &Res, ++ const MCAsmLayout *Layout) const; ++ void AddValueSymbols(MCAssembler *) const; ++ const MCSection *FindAssociatedSection() const { ++ return getSubExpr()->FindAssociatedSection(); ++ } ++ ++ void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const; ++ ++ static bool classof(const MCExpr *E) { ++ return E->getKind() == MCExpr::Target; ++ } ++ ++ static bool classof(const SparcMCExpr *) { return true; } ++ ++ ++}; ++ ++} // end namespace llvm. ++ ++#endif diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198030-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198030-sparc.diff new file mode 100644 index 0000000..7ab4291 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198030-sparc.diff @@ -0,0 +1,678 @@ +Pull in r198030 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Lower and MachineInstr to MC and print assembly using MCInstPrinter. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp +@@ -0,0 +1,40 @@ ++//===-- SparcTargetStreamer.cpp - Sparc Target Streamer Methods -----------===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++// ++// This file provides Sparc specific target streamer methods. ++// ++//===----------------------------------------------------------------------===// ++ ++#include "SparcTargetStreamer.h" ++#include "InstPrinter/SparcInstPrinter.h" ++#include "llvm/Support/FormattedStream.h" ++ ++using namespace llvm; ++ ++// pin vtable to this file ++void SparcTargetStreamer::anchor() {} ++ ++SparcTargetAsmStreamer::SparcTargetAsmStreamer(formatted_raw_ostream &OS) ++ : OS(OS) {} ++ ++void SparcTargetAsmStreamer::emitSparcRegisterIgnore(unsigned reg) { ++ OS << "\t.register " ++ << "%" << StringRef(SparcInstPrinter::getRegisterName(reg)).lower() ++ << ", #ignore\n"; ++} ++ ++void SparcTargetAsmStreamer::emitSparcRegisterScratch(unsigned reg) { ++ OS << "\t.register " ++ << "%" << StringRef(SparcInstPrinter::getRegisterName(reg)).lower() ++ << ", #scratch\n"; ++} ++ ++MCELFStreamer &SparcTargetELFStreamer::getStreamer() { ++ return static_cast<MCELFStreamer &>(*Streamer); ++} +Index: lib/Target/Sparc/MCTargetDesc/LLVMBuild.txt +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/LLVMBuild.txt ++++ lib/Target/Sparc/MCTargetDesc/LLVMBuild.txt +@@ -19,5 +19,5 @@ + type = Library + name = SparcDesc + parent = Sparc +-required_libraries = MC SparcInfo Support ++required_libraries = MC SparcAsmPrinter SparcInfo Support + add_to_library_groups = Sparc +Index: lib/Target/Sparc/MCTargetDesc/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/CMakeLists.txt ++++ lib/Target/Sparc/MCTargetDesc/CMakeLists.txt +@@ -2,6 +2,7 @@ add_llvm_library(LLVMSparcDesc + SparcMCTargetDesc.cpp + SparcMCAsmInfo.cpp + SparcMCExpr.cpp ++ SparcTargetStreamer.cpp + ) + + add_dependencies(LLVMSparcDesc SparcCommonTableGen) +Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +@@ -13,6 +13,8 @@ + + #include "SparcMCTargetDesc.h" + #include "SparcMCAsmInfo.h" ++#include "SparcTargetStreamer.h" ++#include "InstPrinter/SparcInstPrinter.h" + #include "llvm/MC/MCCodeGenInfo.h" + #include "llvm/MC/MCInstrInfo.h" + #include "llvm/MC/MCRegisterInfo.h" +@@ -86,6 +88,28 @@ static MCCodeGenInfo *createSparcV9MCCodeGenInfo(S + X->InitMCCodeGenInfo(RM, CM, OL); + return X; + } ++ ++static MCStreamer * ++createMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, ++ bool isVerboseAsm, bool useLoc, bool useCFI, ++ bool useDwarfDirectory, MCInstPrinter *InstPrint, ++ MCCodeEmitter *CE, MCAsmBackend *TAB, bool ShowInst) { ++ SparcTargetAsmStreamer *S = new SparcTargetAsmStreamer(OS); ++ ++ return llvm::createAsmStreamer(Ctx, S, OS, isVerboseAsm, useLoc, useCFI, ++ useDwarfDirectory, InstPrint, CE, TAB, ++ ShowInst); ++} ++ ++static MCInstPrinter *createSparcMCInstPrinter(const Target &T, ++ unsigned SyntaxVariant, ++ const MCAsmInfo &MAI, ++ const MCInstrInfo &MII, ++ const MCRegisterInfo &MRI, ++ const MCSubtargetInfo &STI) { ++ return new SparcInstPrinter(MAI, MII, MRI); ++} ++ + extern "C" void LLVMInitializeSparcTargetMC() { + // Register the MC asm info. + RegisterMCAsmInfo<SparcELFMCAsmInfo> X(TheSparcTarget); +@@ -106,4 +130,15 @@ extern "C" void LLVMInitializeSparcTargetMC() { + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(TheSparcTarget, + createSparcMCSubtargetInfo); ++ ++ TargetRegistry::RegisterAsmStreamer(TheSparcTarget, ++ createMCAsmStreamer); ++ TargetRegistry::RegisterAsmStreamer(TheSparcV9Target, ++ createMCAsmStreamer); ++ ++ // Register the MCInstPrinter ++ TargetRegistry::RegisterMCInstPrinter(TheSparcTarget, ++ createSparcMCInstPrinter); ++ TargetRegistry::RegisterMCInstPrinter(TheSparcV9Target, ++ createSparcMCInstPrinter); + } +Index: lib/Target/Sparc/SparcTargetStreamer.h +=================================================================== +--- lib/Target/Sparc/SparcTargetStreamer.h ++++ lib/Target/Sparc/SparcTargetStreamer.h +@@ -0,0 +1,47 @@ ++//===-- SparcTargetStreamer.h - Sparc Target Streamer ----------*- C++ -*--===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#ifndef SPARCTARGETSTREAMER_H ++#define SPARCTARGETSTREAMER_H ++ ++#include "llvm/MC/MCELFStreamer.h" ++#include "llvm/MC/MCStreamer.h" ++ ++namespace llvm { ++class SparcTargetStreamer : public MCTargetStreamer { ++ virtual void anchor(); ++ ++public: ++ /// Emit ".register <reg>, #ignore". ++ virtual void emitSparcRegisterIgnore(unsigned reg) = 0; ++ /// Emit ".register <reg>, #scratch". ++ virtual void emitSparcRegisterScratch(unsigned reg) = 0; ++}; ++ ++// This part is for ascii assembly output ++class SparcTargetAsmStreamer : public SparcTargetStreamer { ++ formatted_raw_ostream &OS; ++ ++public: ++ SparcTargetAsmStreamer(formatted_raw_ostream &OS); ++ virtual void emitSparcRegisterIgnore(unsigned reg); ++ virtual void emitSparcRegisterScratch(unsigned reg); ++ ++}; ++ ++// This part is for ELF object output ++class SparcTargetELFStreamer : public SparcTargetStreamer { ++public: ++ MCELFStreamer &getStreamer(); ++ virtual void emitSparcRegisterIgnore(unsigned reg) {} ++ virtual void emitSparcRegisterScratch(unsigned reg) {} ++}; ++} // end namespace llvm ++ ++#endif +Index: lib/Target/Sparc/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/CMakeLists.txt ++++ lib/Target/Sparc/CMakeLists.txt +@@ -23,6 +23,7 @@ add_llvm_target(SparcCodeGen + SparcSelectionDAGInfo.cpp + SparcJITInfo.cpp + SparcCodeEmitter.cpp ++ SparcMCInstLower.cpp + ) + + add_dependencies(LLVMSparcCodeGen SparcCommonTableGen intrinsics_gen) +Index: lib/Target/Sparc/Sparc.td +=================================================================== +--- lib/Target/Sparc/Sparc.td ++++ lib/Target/Sparc/Sparc.td +@@ -65,6 +65,10 @@ def : Proc<"ultrasparc", [FeatureV9, FeatureV + def : Proc<"ultrasparc3", [FeatureV9, FeatureV8Deprecated]>; + def : Proc<"ultrasparc3-vis", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>; + ++def SparcAsmWriter : AsmWriter { ++ string AsmWriterClassName = "InstPrinter"; ++ bit isMCAsmWriter = 1; ++} + + //===----------------------------------------------------------------------===// + // Declare the target which we are implementing +@@ -73,4 +77,6 @@ def : Proc<"ultrasparc3-vis", [FeatureV9, FeatureV + def Sparc : Target { + // Pull in Instruction Info: + let InstructionSet = SparcInstrInfo; ++ ++ let AssemblyWriters = [SparcAsmWriter]; + } +Index: lib/Target/Sparc/SparcMCInstLower.cpp +=================================================================== +--- lib/Target/Sparc/SparcMCInstLower.cpp ++++ lib/Target/Sparc/SparcMCInstLower.cpp +@@ -0,0 +1,141 @@ ++//===-- SparcMCInstLower.cpp - Convert Sparc MachineInstr to MCInst -------===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++// ++// This file contains code to lower Sparc MachineInstrs to their corresponding ++// MCInst records. ++// ++//===----------------------------------------------------------------------===// ++ ++#include "Sparc.h" ++#include "MCTargetDesc/SparcBaseInfo.h" ++#include "MCTargetDesc/SparcMCExpr.h" ++#include "llvm/CodeGen/AsmPrinter.h" ++#include "llvm/CodeGen/MachineFunction.h" ++#include "llvm/CodeGen/MachineInstr.h" ++#include "llvm/CodeGen/MachineOperand.h" ++#include "llvm/MC/MCContext.h" ++#include "llvm/MC/MCAsmInfo.h" ++#include "llvm/MC/MCExpr.h" ++#include "llvm/MC/MCInst.h" ++#include "llvm/Target/Mangler.h" ++#include "llvm/ADT/SmallString.h" ++ ++using namespace llvm; ++ ++ ++static MCOperand LowerSymbolOperand(const MachineInstr *MI, ++ const MachineOperand &MO, ++ AsmPrinter &AP) { ++ ++ SparcMCExpr::VariantKind Kind; ++ const MCSymbol *Symbol = 0; ++ ++ unsigned TF = MO.getTargetFlags(); ++ ++ switch(TF) { ++ default: llvm_unreachable("Unknown target flags on operand"); ++ case SPII::MO_NO_FLAG: Kind = SparcMCExpr::VK_Sparc_None; break; ++ case SPII::MO_LO: Kind = SparcMCExpr::VK_Sparc_LO; break; ++ case SPII::MO_HI: Kind = SparcMCExpr::VK_Sparc_HI; break; ++ case SPII::MO_H44: Kind = SparcMCExpr::VK_Sparc_H44; break; ++ case SPII::MO_M44: Kind = SparcMCExpr::VK_Sparc_M44; break; ++ case SPII::MO_L44: Kind = SparcMCExpr::VK_Sparc_L44; break; ++ case SPII::MO_HH: Kind = SparcMCExpr::VK_Sparc_HH; break; ++ case SPII::MO_HM: Kind = SparcMCExpr::VK_Sparc_HM; break; ++ case SPII::MO_TLS_GD_HI22: Kind = SparcMCExpr::VK_Sparc_TLS_GD_HI22; break; ++ case SPII::MO_TLS_GD_LO10: Kind = SparcMCExpr::VK_Sparc_TLS_GD_LO10; break; ++ case SPII::MO_TLS_GD_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_GD_ADD; break; ++ case SPII::MO_TLS_GD_CALL: Kind = SparcMCExpr::VK_Sparc_TLS_GD_CALL; break; ++ case SPII::MO_TLS_LDM_HI22: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_HI22; break; ++ case SPII::MO_TLS_LDM_LO10: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_LO10; break; ++ case SPII::MO_TLS_LDM_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_ADD; break; ++ case SPII::MO_TLS_LDM_CALL: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_CALL; break; ++ case SPII::MO_TLS_LDO_HIX22:Kind = SparcMCExpr::VK_Sparc_TLS_LDO_HIX22; break; ++ case SPII::MO_TLS_LDO_LOX10:Kind = SparcMCExpr::VK_Sparc_TLS_LDO_LOX10; break; ++ case SPII::MO_TLS_LDO_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_LDO_ADD; break; ++ case SPII::MO_TLS_IE_HI22: Kind = SparcMCExpr::VK_Sparc_TLS_IE_HI22; break; ++ case SPII::MO_TLS_IE_LO10: Kind = SparcMCExpr::VK_Sparc_TLS_IE_LO10; break; ++ case SPII::MO_TLS_IE_LD: Kind = SparcMCExpr::VK_Sparc_TLS_IE_LD; break; ++ case SPII::MO_TLS_IE_LDX: Kind = SparcMCExpr::VK_Sparc_TLS_IE_LDX; break; ++ case SPII::MO_TLS_IE_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_IE_ADD; break; ++ case SPII::MO_TLS_LE_HIX22: Kind = SparcMCExpr::VK_Sparc_TLS_LE_HIX22; break; ++ case SPII::MO_TLS_LE_LOX10: Kind = SparcMCExpr::VK_Sparc_TLS_LE_LOX10; break; ++ } ++ ++ switch(MO.getType()) { ++ default: llvm_unreachable("Unknown type in LowerSymbolOperand"); ++ case MachineOperand::MO_MachineBasicBlock: ++ Symbol = MO.getMBB()->getSymbol(); ++ break; ++ ++ case MachineOperand::MO_GlobalAddress: ++ Symbol = AP.getSymbol(MO.getGlobal()); ++ break; ++ ++ case MachineOperand::MO_BlockAddress: ++ Symbol = AP.GetBlockAddressSymbol(MO.getBlockAddress()); ++ break; ++ ++ case MachineOperand::MO_ExternalSymbol: ++ Symbol = AP.GetExternalSymbolSymbol(MO.getSymbolName()); ++ break; ++ ++ case MachineOperand::MO_ConstantPoolIndex: ++ Symbol = AP.GetCPISymbol(MO.getIndex()); ++ break; ++ } ++ ++ const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Symbol, ++ AP.OutContext); ++ const SparcMCExpr *expr = SparcMCExpr::Create(Kind, MCSym, ++ AP.OutContext); ++ return MCOperand::CreateExpr(expr); ++} ++ ++static MCOperand LowerOperand(const MachineInstr *MI, ++ const MachineOperand &MO, ++ AsmPrinter &AP) { ++ switch(MO.getType()) { ++ default: llvm_unreachable("unknown operand type"); break; ++ case MachineOperand::MO_Register: ++ if (MO.isImplicit()) ++ break; ++ return MCOperand::CreateReg(MO.getReg()); ++ ++ case MachineOperand::MO_Immediate: ++ return MCOperand::CreateImm(MO.getImm()); ++ ++ case MachineOperand::MO_MachineBasicBlock: ++ case MachineOperand::MO_GlobalAddress: ++ case MachineOperand::MO_BlockAddress: ++ case MachineOperand::MO_ExternalSymbol: ++ case MachineOperand::MO_ConstantPoolIndex: ++ return LowerSymbolOperand(MI, MO, AP); ++ ++ case MachineOperand::MO_RegisterMask: break; ++ ++ } ++ return MCOperand(); ++} ++ ++void llvm::LowerSparcMachineInstrToMCInst(const MachineInstr *MI, ++ MCInst &OutMI, ++ AsmPrinter &AP) ++{ ++ ++ OutMI.setOpcode(MI->getOpcode()); ++ ++ for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { ++ const MachineOperand &MO = MI->getOperand(i); ++ MCOperand MCOp = LowerOperand(MI, MO, AP); ++ ++ if (MCOp.isValid()) ++ OutMI.addOperand(MCOp); ++ } ++} +Index: lib/Target/Sparc/Sparc.h +=================================================================== +--- lib/Target/Sparc/Sparc.h ++++ lib/Target/Sparc/Sparc.h +@@ -23,6 +23,9 @@ namespace llvm { + class FunctionPass; + class SparcTargetMachine; + class formatted_raw_ostream; ++ class AsmPrinter; ++ class MCInst; ++ class MachineInstr; + + FunctionPass *createSparcISelDag(SparcTargetMachine &TM); + FunctionPass *createSparcDelaySlotFillerPass(TargetMachine &TM); +@@ -29,6 +32,9 @@ namespace llvm { + FunctionPass *createSparcJITCodeEmitterPass(SparcTargetMachine &TM, + JITCodeEmitter &JCE); + ++ void LowerSparcMachineInstrToMCInst(const MachineInstr *MI, ++ MCInst &OutMI, ++ AsmPrinter &AP); + } // end namespace llvm; + + namespace llvm { +Index: lib/Target/Sparc/SparcAsmPrinter.cpp +=================================================================== +--- lib/Target/Sparc/SparcAsmPrinter.cpp ++++ lib/Target/Sparc/SparcAsmPrinter.cpp +@@ -16,12 +16,17 @@ + #include "Sparc.h" + #include "SparcInstrInfo.h" + #include "SparcTargetMachine.h" ++#include "SparcTargetStreamer.h" ++#include "InstPrinter/SparcInstPrinter.h" + #include "MCTargetDesc/SparcBaseInfo.h" ++#include "MCTargetDesc/SparcMCExpr.h" + #include "llvm/ADT/SmallString.h" + #include "llvm/CodeGen/AsmPrinter.h" + #include "llvm/CodeGen/MachineInstr.h" + #include "llvm/CodeGen/MachineRegisterInfo.h" + #include "llvm/MC/MCAsmInfo.h" ++#include "llvm/MC/MCContext.h" ++#include "llvm/MC/MCInst.h" + #include "llvm/MC/MCStreamer.h" + #include "llvm/MC/MCSymbol.h" + #include "llvm/Support/TargetRegistry.h" +@@ -31,6 +36,9 @@ using namespace llvm; + + namespace { + class SparcAsmPrinter : public AsmPrinter { ++ SparcTargetStreamer &getTargetStreamer() { ++ return static_cast<SparcTargetStreamer&>(OutStreamer.getTargetStreamer()); ++ } + public: + explicit SparcAsmPrinter(TargetMachine &TM, MCStreamer &Streamer) + : AsmPrinter(TM, Streamer) {} +@@ -45,14 +53,11 @@ namespace { + void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); + + virtual void EmitFunctionBodyStart(); +- virtual void EmitInstruction(const MachineInstr *MI) { +- SmallString<128> Str; +- raw_svector_ostream OS(Str); +- printInstruction(MI, OS); +- OutStreamer.EmitRawText(OS.str()); ++ virtual void EmitInstruction(const MachineInstr *MI); ++ ++ static const char *getRegisterName(unsigned RegNo) { ++ return SparcInstPrinter::getRegisterName(RegNo); + } +- void printInstruction(const MachineInstr *MI, raw_ostream &OS);// autogen'd. +- static const char *getRegisterName(unsigned RegNo); + + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, +@@ -61,25 +66,139 @@ namespace { + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); + +- bool printGetPCX(const MachineInstr *MI, unsigned OpNo, raw_ostream &OS); +- + virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) + const; +- void EmitGlobalRegisterDecl(unsigned reg) { +- SmallString<128> Str; +- raw_svector_ostream OS(Str); +- OS << "\t.register " +- << "%" << StringRef(getRegisterName(reg)).lower() +- << ", " +- << ((reg == SP::G6 || reg == SP::G7)? "#ignore" : "#scratch"); +- OutStreamer.EmitRawText(OS.str()); +- } + + }; + } // end of anonymous namespace + +-#include "SparcGenAsmWriter.inc" ++static MCOperand createPCXCallOP(MCSymbol *Label, ++ MCContext &OutContext) ++{ ++ const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Label, ++ OutContext); ++ const SparcMCExpr *expr = SparcMCExpr::Create(SparcMCExpr::VK_Sparc_None, ++ MCSym, OutContext); ++ return MCOperand::CreateExpr(expr); ++} + ++static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind, ++ MCSymbol *GOTLabel, MCSymbol *StartLabel, ++ MCSymbol *CurLabel, ++ MCContext &OutContext) ++{ ++ const MCSymbolRefExpr *GOT = MCSymbolRefExpr::Create(GOTLabel, OutContext); ++ const MCSymbolRefExpr *Start = MCSymbolRefExpr::Create(StartLabel, ++ OutContext); ++ const MCSymbolRefExpr *Cur = MCSymbolRefExpr::Create(CurLabel, ++ OutContext); ++ ++ const MCBinaryExpr *Sub = MCBinaryExpr::CreateSub(Cur, Start, OutContext); ++ const MCBinaryExpr *Add = MCBinaryExpr::CreateAdd(GOT, Sub, OutContext); ++ const SparcMCExpr *expr = SparcMCExpr::Create(Kind, ++ Add, OutContext); ++ return MCOperand::CreateExpr(expr); ++} ++ ++static void EmitCall(MCStreamer &OutStreamer, ++ MCOperand &Callee) ++{ ++ MCInst CallInst; ++ CallInst.setOpcode(SP::CALL); ++ CallInst.addOperand(Callee); ++ OutStreamer.EmitInstruction(CallInst); ++} ++ ++static void EmitSETHI(MCStreamer &OutStreamer, ++ MCOperand &Imm, MCOperand &RD) ++{ ++ MCInst SETHIInst; ++ SETHIInst.setOpcode(SP::SETHIi); ++ SETHIInst.addOperand(RD); ++ SETHIInst.addOperand(Imm); ++ OutStreamer.EmitInstruction(SETHIInst); ++} ++ ++static void EmitOR(MCStreamer &OutStreamer, MCOperand &RS1, ++ MCOperand &Imm, MCOperand &RD) ++{ ++ MCInst ORInst; ++ ORInst.setOpcode(SP::ORri); ++ ORInst.addOperand(RD); ++ ORInst.addOperand(RS1); ++ ORInst.addOperand(Imm); ++ OutStreamer.EmitInstruction(ORInst); ++} ++ ++void EmitADD(MCStreamer &OutStreamer, ++ MCOperand &RS1, MCOperand &RS2, MCOperand &RD) ++{ ++ MCInst ADDInst; ++ ADDInst.setOpcode(SP::ADDrr); ++ ADDInst.addOperand(RD); ++ ADDInst.addOperand(RS1); ++ ADDInst.addOperand(RS2); ++ OutStreamer.EmitInstruction(ADDInst); ++} ++ ++static void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI, ++ MCStreamer &OutStreamer, ++ MCContext &OutContext) ++{ ++ const MachineOperand &MO = MI->getOperand(0); ++ MCSymbol *StartLabel = OutContext.CreateTempSymbol(); ++ MCSymbol *EndLabel = OutContext.CreateTempSymbol(); ++ MCSymbol *SethiLabel = OutContext.CreateTempSymbol(); ++ MCSymbol *GOTLabel = ++ OutContext.GetOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_")); ++ ++ assert(MO.getReg() != SP::O7 && ++ "%o7 is assigned as destination for getpcx!"); ++ ++ MCOperand MCRegOP = MCOperand::CreateReg(MO.getReg()); ++ MCOperand RegO7 = MCOperand::CreateReg(SP::O7); ++ ++ // <StartLabel>: ++ // call <EndLabel> ++ // <SethiLabel>: ++ // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO> ++ // <EndLabel>: ++ // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO> ++ // add <MO>, %o7, <MO> ++ ++ OutStreamer.EmitLabel(StartLabel); ++ MCOperand Callee = createPCXCallOP(EndLabel, OutContext); ++ EmitCall(OutStreamer, Callee); ++ OutStreamer.EmitLabel(SethiLabel); ++ MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_HI, ++ GOTLabel, StartLabel, SethiLabel, ++ OutContext); ++ EmitSETHI(OutStreamer, hiImm, MCRegOP); ++ OutStreamer.EmitLabel(EndLabel); ++ MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_LO, ++ GOTLabel, StartLabel, EndLabel, ++ OutContext); ++ EmitOR(OutStreamer, MCRegOP, loImm, MCRegOP); ++ EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP); ++} ++ ++void SparcAsmPrinter::EmitInstruction(const MachineInstr *MI) ++{ ++ MCInst TmpInst; ++ ++ switch (MI->getOpcode()) { ++ default: break; ++ case TargetOpcode::DBG_VALUE: ++ // FIXME: Debug Value. ++ return; ++ case SP::GETPCX: ++ LowerGETPCXAndEmitMCInsts(MI, OutStreamer, OutContext); ++ return; ++ } ++ LowerSparcMachineInstrToMCInst(MI, TmpInst, *this); ++ OutStreamer.EmitInstruction(TmpInst); ++} ++ + void SparcAsmPrinter::EmitFunctionBodyStart() { + if (!TM.getSubtarget<SparcSubtarget>().is64Bit()) + return; +@@ -90,7 +209,11 @@ void SparcAsmPrinter::EmitFunctionBodyStart() { + unsigned reg = globalRegs[i]; + if (MRI.use_empty(reg)) + continue; +- EmitGlobalRegisterDecl(reg); ++ ++ if (reg == SP::G6 || reg == SP::G7) ++ getTargetStreamer().emitSparcRegisterIgnore(reg); ++ else ++ getTargetStreamer().emitSparcRegisterScratch(reg); + } + } + +@@ -226,46 +349,6 @@ void SparcAsmPrinter::printMemOperand(const Machin + printOperand(MI, opNum+1, O); + } + +-bool SparcAsmPrinter::printGetPCX(const MachineInstr *MI, unsigned opNum, +- raw_ostream &O) { +- std::string operand = ""; +- const MachineOperand &MO = MI->getOperand(opNum); +- switch (MO.getType()) { +- default: llvm_unreachable("Operand is not a register"); +- case MachineOperand::MO_Register: +- assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) && +- "Operand is not a physical register "); +- assert(MO.getReg() != SP::O7 && +- "%o7 is assigned as destination for getpcx!"); +- operand = "%" + StringRef(getRegisterName(MO.getReg())).lower(); +- break; +- } +- +- unsigned mfNum = MI->getParent()->getParent()->getFunctionNumber(); +- unsigned bbNum = MI->getParent()->getNumber(); +- +- O << '\n' << ".LLGETPCH" << mfNum << '_' << bbNum << ":\n"; +- O << "\tcall\t.LLGETPC" << mfNum << '_' << bbNum << '\n' ; +- +- O << "\t sethi\t" +- << "%hi(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum +- << ")), " << operand << '\n' ; +- +- O << ".LLGETPC" << mfNum << '_' << bbNum << ":\n" ; +- O << "\tor\t" << operand +- << ", %lo(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum +- << ")), " << operand << '\n'; +- O << "\tadd\t" << operand << ", %o7, " << operand << '\n'; +- +- return true; +-} +- +-void SparcAsmPrinter::printCCOperand(const MachineInstr *MI, int opNum, +- raw_ostream &O) { +- int CC = (int)MI->getOperand(opNum).getImm(); +- O << SPARCCondCodeToString((SPCC::CondCodes)CC); +-} +- + /// PrintAsmOperand - Print out an operand for an inline asm expression. + /// + bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, +Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp +=================================================================== +--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp ++++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp +@@ -23,8 +23,7 @@ + using namespace llvm; + + #define GET_INSTRUCTION_NAME +-// Uncomment the following line once we are ready to use MCAsmWriter. +-//#include "SparcGenAsmWriter.inc" ++#include "SparcGenAsmWriter.inc" + + void SparcInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const + { +Index: test/CodeGen/SPARC/exception.ll +=================================================================== +--- test/CodeGen/SPARC/exception.ll ++++ test/CodeGen/SPARC/exception.ll +@@ -11,7 +11,7 @@ + + ; CHECK-LABEL: main: + ; CHECK: .cfi_startproc +-; CHECK: .cfi_def_cfa_register 30 ++; CHECK: .cfi_def_cfa_register {{30|%fp}} + ; CHECK: .cfi_window_save + ; CHECK: .cfi_register 15, 31 + diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198145-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198145-sparc.diff new file mode 100644 index 0000000..2429e52 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198145-sparc.diff @@ -0,0 +1,166 @@ +Pull in r198145 from upstream llvm trunk (by Venkatraman Govindaraju): + + [SparcV9]: Implement lowering of long double (fp128) arguments in Sparc64 ABI. + Also, pass fp128 arguments to varargs through integer registers if necessary. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/CodeGen/SPARC/64abi.ll +=================================================================== +--- test/CodeGen/SPARC/64abi.ll ++++ test/CodeGen/SPARC/64abi.ll +@@ -411,3 +411,33 @@ entry: + } + + declare i32 @use_buf(i32, i8*) ++ ++; CHECK-LABEL: test_fp128_args ++; CHECK-DAG: std %f0, [%fp+{{.+}}] ++; CHECK-DAG: std %f2, [%fp+{{.+}}] ++; CHECK-DAG: std %f6, [%fp+{{.+}}] ++; CHECK-DAG: std %f4, [%fp+{{.+}}] ++; CHECK: add %fp, [[Offset:[0-9]+]], %o0 ++; CHECK: call _Qp_add ++; CHECK: ldd [%fp+[[Offset]]], %f0 ++define fp128 @test_fp128_args(fp128 %a, fp128 %b) { ++entry: ++ %0 = fadd fp128 %a, %b ++ ret fp128 %0 ++} ++ ++declare i64 @receive_fp128(i64 %a, ...) ++ ++; CHECK-LABEL: test_fp128_variable_args ++; CHECK-DAG: std %f4, [%sp+[[Offset0:[0-9]+]]] ++; CHECK-DAG: std %f6, [%sp+[[Offset1:[0-9]+]]] ++; CHECK-DAG: ldx [%sp+[[Offset0]]], %o2 ++; CHECK-DAG: ldx [%sp+[[Offset1]]], %o3 ++; CHECK: call receive_fp128 ++define i64 @test_fp128_variable_args(i64 %a, fp128 %b) { ++entry: ++ %0 = call i64 (i64, ...)* @receive_fp128(i64 %a, fp128 %b) ++ ret i64 %0 ++} ++ ++ +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -80,11 +80,14 @@ static bool CC_Sparc_Assign_f64(unsigned &ValNo, M + static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT, + MVT &LocVT, CCValAssign::LocInfo &LocInfo, + ISD::ArgFlagsTy &ArgFlags, CCState &State) { +- assert((LocVT == MVT::f32 || LocVT.getSizeInBits() == 64) && ++ assert((LocVT == MVT::f32 || LocVT == MVT::f128 ++ || LocVT.getSizeInBits() == 64) && + "Can't handle non-64 bits locations"); + + // Stack space is allocated for all arguments starting from [%fp+BIAS+128]. +- unsigned Offset = State.AllocateStack(8, 8); ++ unsigned size = (LocVT == MVT::f128) ? 16 : 8; ++ unsigned alignment = (LocVT == MVT::f128) ? 16 : 8; ++ unsigned Offset = State.AllocateStack(size, alignment); + unsigned Reg = 0; + + if (LocVT == MVT::i64 && Offset < 6*8) +@@ -96,6 +99,9 @@ static bool CC_Sparc64_Full(unsigned &ValNo, MVT & + else if (LocVT == MVT::f32 && Offset < 16*8) + // Promote floats to %f1, %f3, ... + Reg = SP::F1 + Offset/4; ++ else if (LocVT == MVT::f128 && Offset < 16*8) ++ // Promote long doubles to %q0-%q28. (Which LLVM calls Q0-Q7). ++ Reg = SP::Q0 + Offset/16; + + // Promote to register when possible, otherwise use the stack slot. + if (Reg) { +@@ -998,9 +1004,10 @@ static void fixupVariableFloatArgs(SmallVectorImpl + ArrayRef<ISD::OutputArg> Outs) { + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + const CCValAssign &VA = ArgLocs[i]; ++ MVT ValTy = VA.getLocVT(); + // FIXME: What about f32 arguments? C promotes them to f64 when calling + // varargs functions. +- if (!VA.isRegLoc() || VA.getLocVT() != MVT::f64) ++ if (!VA.isRegLoc() || (ValTy != MVT::f64 && ValTy != MVT::f128)) + continue; + // The fixed arguments to a varargs function still go in FP registers. + if (Outs[VA.getValNo()].IsFixed) +@@ -1010,15 +1017,25 @@ static void fixupVariableFloatArgs(SmallVectorImpl + CCValAssign NewVA; + + // Determine the offset into the argument array. +- unsigned Offset = 8 * (VA.getLocReg() - SP::D0); ++ unsigned firstReg = (ValTy == MVT::f64) ? SP::D0 : SP::Q0; ++ unsigned argSize = (ValTy == MVT::f64) ? 8 : 16; ++ unsigned Offset = argSize * (VA.getLocReg() - firstReg); + assert(Offset < 16*8 && "Offset out of range, bad register enum?"); + + if (Offset < 6*8) { + // This argument should go in %i0-%i5. + unsigned IReg = SP::I0 + Offset/8; +- // Full register, just bitconvert into i64. +- NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(), +- IReg, MVT::i64, CCValAssign::BCvt); ++ if (ValTy == MVT::f64) ++ // Full register, just bitconvert into i64. ++ NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(), ++ IReg, MVT::i64, CCValAssign::BCvt); ++ else { ++ assert(ValTy == MVT::f128 && "Unexpected type!"); ++ // Full register, just bitconvert into i128 -- We will lower this into ++ // two i64s in LowerCall_64. ++ NewVA = CCValAssign::getCustomReg(VA.getValNo(), VA.getValVT(), ++ IReg, MVT::i128, CCValAssign::BCvt); ++ } + } else { + // This needs to go to memory, we're out of integer registers. + NewVA = CCValAssign::getMem(VA.getValNo(), VA.getValVT(), +@@ -1094,11 +1111,46 @@ SparcTargetLowering::LowerCall_64(TargetLowering:: + Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg); + break; + case CCValAssign::BCvt: +- Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg); ++ // fixupVariableFloatArgs() may create bitcasts from f128 to i128. But ++ // SPARC does not support i128 natively. Lower it into two i64, see below. ++ if (!VA.needsCustom() || VA.getValVT() != MVT::f128 ++ || VA.getLocVT() != MVT::i128) ++ Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg); + break; + } + + if (VA.isRegLoc()) { ++ if (VA.needsCustom() && VA.getValVT() == MVT::f128 ++ && VA.getLocVT() == MVT::i128) { ++ // Store and reload into the interger register reg and reg+1. ++ unsigned Offset = 8 * (VA.getLocReg() - SP::I0); ++ unsigned StackOffset = Offset + Subtarget->getStackPointerBias() + 128; ++ SDValue StackPtr = DAG.getRegister(SP::O6, getPointerTy()); ++ SDValue HiPtrOff = DAG.getIntPtrConstant(StackOffset); ++ HiPtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr, ++ HiPtrOff); ++ SDValue LoPtrOff = DAG.getIntPtrConstant(StackOffset + 8); ++ LoPtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr, ++ LoPtrOff); ++ ++ // Store to %sp+BIAS+128+Offset ++ SDValue Store = DAG.getStore(Chain, DL, Arg, HiPtrOff, ++ MachinePointerInfo(), ++ false, false, 0); ++ // Load into Reg and Reg+1 ++ SDValue Hi64 = DAG.getLoad(MVT::i64, DL, Store, HiPtrOff, ++ MachinePointerInfo(), ++ false, false, false, 0); ++ SDValue Lo64 = DAG.getLoad(MVT::i64, DL, Store, LoPtrOff, ++ MachinePointerInfo(), ++ false, false, false, 0); ++ RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()), ++ Hi64)); ++ RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()+1), ++ Lo64)); ++ continue; ++ } ++ + // The custom bit on an i32 return value indicates that it should be + // passed in the high bits of the register. + if (VA.getValVT() == MVT::i32 && VA.needsCustom()) { diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198149-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198149-sparc.diff new file mode 100644 index 0000000..912daf3 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198149-sparc.diff @@ -0,0 +1,54 @@ +Pull in r198149 from upstream llvm trunk (by Venkatraman Govindaraju): + + [SparcV9] For codegen generated library calls that return float, set inreg flag manually in LowerCall(). + This makes the sparc backend to generate Sparc64 ABI compliant code. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -1252,6 +1252,12 @@ SparcTargetLowering::LowerCall_64(TargetLowering:: + SmallVector<CCValAssign, 16> RVLocs; + CCState RVInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(), + DAG.getTarget(), RVLocs, *DAG.getContext()); ++ ++ // Set inreg flag manually for codegen generated library calls that ++ // return float. ++ if (CLI.Ins.size() == 1 && CLI.Ins[0].VT == MVT::f32 && CLI.CS == 0) ++ CLI.Ins[0].Flags.setInReg(); ++ + RVInfo.AnalyzeCallResult(CLI.Ins, CC_Sparc64); + + // Copy all of the result registers out of their specified physreg. +Index: test/CodeGen/SPARC/64abi.ll +=================================================================== +--- test/CodeGen/SPARC/64abi.ll ++++ test/CodeGen/SPARC/64abi.ll +@@ -440,4 +440,25 @@ entry: + ret i64 %0 + } + ++; CHECK-LABEL: test_call_libfunc ++; CHECK: st %f1, [%fp+[[Offset0:[0-9]+]]] ++; CHECK: fmovs %f3, %f1 ++; CHECK: call cosf ++; CHECK: st %f0, [%fp+[[Offset1:[0-9]+]]] ++; CHECK: ld [%fp+[[Offset0]]], %f1 ++; CHECK: call sinf ++; CHECK: ld [%fp+[[Offset1]]], %f1 ++; CHECK: fmuls %f1, %f0, %f0 + ++define inreg float @test_call_libfunc(float %arg0, float %arg1) { ++entry: ++ %0 = tail call inreg float @cosf(float %arg1) ++ %1 = tail call inreg float @sinf(float %arg0) ++ %2 = fmul float %0, %1 ++ ret float %2 ++} ++ ++declare inreg float @cosf(float %arg) readnone nounwind ++declare inreg float @sinf(float %arg) readnone nounwind ++ ++ diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198157-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198157-sparc.diff new file mode 100644 index 0000000..42ef3db --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198157-sparc.diff @@ -0,0 +1,368 @@ +Pull in r198157 from upstream llvm trunk (by Venkatraman Govindaraju): + + [SparcV9] Use separate instruction patterns for 64 bit arithmetic instructions instead of reusing 32 bit instruction patterns. + This is done to avoid spilling the result of the 64-bit instructions to a 4-byte slot. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcAsmPrinter.cpp +=================================================================== +--- lib/Target/Sparc/SparcAsmPrinter.cpp ++++ lib/Target/Sparc/SparcAsmPrinter.cpp +@@ -227,7 +227,7 @@ void SparcAsmPrinter::printOperand(const MachineIn + if (MI->getOpcode() == SP::CALL) + assert(TF == SPII::MO_NO_FLAG && + "Cannot handle target flags on call address"); +- else if (MI->getOpcode() == SP::SETHIi) ++ else if (MI->getOpcode() == SP::SETHIi || MI->getOpcode() == SP::SETHIXi) + assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH + || TF == SPII::MO_TLS_GD_HI22 + || TF == SPII::MO_TLS_LDM_HI22 +@@ -250,7 +250,7 @@ void SparcAsmPrinter::printOperand(const MachineIn + else if (MI->getOpcode() == SP::TLS_LDXrr) + assert(TF == SPII::MO_TLS_IE_LDX && + "Cannot handle target flags on ldx for TLS"); +- else if (MI->getOpcode() == SP::XORri) ++ else if (MI->getOpcode() == SP::XORri || MI->getOpcode() == SP::XORXri) + assert((TF == SPII::MO_TLS_LDO_LOX10 || TF == SPII::MO_TLS_LE_LOX10) && + "Cannot handle target flags on xor for TLS"); + else +Index: lib/Target/Sparc/SparcInstr64Bit.td +=================================================================== +--- lib/Target/Sparc/SparcInstr64Bit.td ++++ lib/Target/Sparc/SparcInstr64Bit.td +@@ -141,32 +141,36 @@ def : Pat<(i64 imm:$val), + let Predicates = [Is64Bit] in { + + // Register-register instructions. ++defm ANDX : F3_12<"and", 0b000001, and, I64Regs, i64, i64imm>; ++defm ORX : F3_12<"or", 0b000010, or, I64Regs, i64, i64imm>; ++defm XORX : F3_12<"xor", 0b000011, xor, I64Regs, i64, i64imm>; + +-def : Pat<(and i64:$a, i64:$b), (ANDrr $a, $b)>; +-def : Pat<(or i64:$a, i64:$b), (ORrr $a, $b)>; +-def : Pat<(xor i64:$a, i64:$b), (XORrr $a, $b)>; ++def ANDXNrr : F3_1<2, 0b000101, ++ (outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c), ++ "andn $b, $c, $dst", ++ [(set i64:$dst, (and i64:$b, (not i64:$c)))]>; ++def ORXNrr : F3_1<2, 0b000110, ++ (outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c), ++ "orn $b, $c, $dst", ++ [(set i64:$dst, (or i64:$b, (not i64:$c)))]>; ++def XNORXrr : F3_1<2, 0b000111, ++ (outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c), ++ "xnor $b, $c, $dst", ++ [(set i64:$dst, (not (xor i64:$b, i64:$c)))]>; + +-def : Pat<(and i64:$a, (not i64:$b)), (ANDNrr $a, $b)>; +-def : Pat<(or i64:$a, (not i64:$b)), (ORNrr $a, $b)>; +-def : Pat<(xor i64:$a, (not i64:$b)), (XNORrr $a, $b)>; ++defm ADDX : F3_12<"add", 0b000000, add, I64Regs, i64, i64imm>; ++defm SUBX : F3_12<"sub", 0b000100, sub, I64Regs, i64, i64imm>; + +-def : Pat<(add i64:$a, i64:$b), (ADDrr $a, $b)>; +-def : Pat<(sub i64:$a, i64:$b), (SUBrr $a, $b)>; +- + def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>; + +-def : Pat<(tlsadd i64:$a, i64:$b, tglobaltlsaddr:$sym), +- (TLS_ADDrr $a, $b, $sym)>; ++def TLS_ADDXrr : F3_1<2, 0b000000, (outs I64Regs:$rd), ++ (ins I64Regs:$rs1, I64Regs:$rs2, TLSSym:$sym), ++ "add $rs1, $rs2, $rd, $sym", ++ [(set i64:$rd, ++ (tlsadd i64:$rs1, i64:$rs2, tglobaltlsaddr:$sym))]>; + + // Register-immediate instructions. + +-def : Pat<(and i64:$a, (i64 simm13:$b)), (ANDri $a, (as_i32imm $b))>; +-def : Pat<(or i64:$a, (i64 simm13:$b)), (ORri $a, (as_i32imm $b))>; +-def : Pat<(xor i64:$a, (i64 simm13:$b)), (XORri $a, (as_i32imm $b))>; +- +-def : Pat<(add i64:$a, (i64 simm13:$b)), (ADDri $a, (as_i32imm $b))>; +-def : Pat<(sub i64:$a, (i64 simm13:$b)), (SUBri $a, (as_i32imm $b))>; +- + def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMPri $a, (as_i32imm $b))>; + + def : Pat<(ctpop i64:$src), (POPCrr $src)>; +@@ -402,3 +406,38 @@ def : Pat<(SPselectfcc (i64 simm11:$t), i64:$f, im + (MOVFCCri (as_i32imm $t), $f, imm:$cond)>; + + } // Predicates = [Is64Bit] ++ ++ ++// 64 bit SETHI ++let Predicates = [Is64Bit] in { ++def SETHIXi : F2_1<0b100, ++ (outs IntRegs:$rd), (ins i64imm:$imm22), ++ "sethi $imm22, $rd", ++ [(set i64:$rd, SETHIimm:$imm22)]>; ++} ++// Global addresses, constant pool entries ++let Predicates = [Is64Bit] in { ++ ++def : Pat<(SPhi tglobaladdr:$in), (SETHIi tglobaladdr:$in)>; ++def : Pat<(SPlo tglobaladdr:$in), (ORXri (i64 G0), tglobaladdr:$in)>; ++def : Pat<(SPhi tconstpool:$in), (SETHIi tconstpool:$in)>; ++def : Pat<(SPlo tconstpool:$in), (ORXri (i64 G0), tconstpool:$in)>; ++ ++// GlobalTLS addresses ++def : Pat<(SPhi tglobaltlsaddr:$in), (SETHIi tglobaltlsaddr:$in)>; ++def : Pat<(SPlo tglobaltlsaddr:$in), (ORXri (i64 G0), tglobaltlsaddr:$in)>; ++def : Pat<(add (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)), ++ (ADDXri (SETHIXi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>; ++def : Pat<(xor (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)), ++ (XORXri (SETHIXi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>; ++ ++// Blockaddress ++def : Pat<(SPhi tblockaddress:$in), (SETHIi tblockaddress:$in)>; ++def : Pat<(SPlo tblockaddress:$in), (ORXri (i64 G0), tblockaddress:$in)>; ++ ++// Add reg, lo. This is used when taking the addr of a global/constpool entry. ++def : Pat<(add iPTR:$r, (SPlo tglobaladdr:$in)), (ADDXri $r, tglobaladdr:$in)>; ++def : Pat<(add iPTR:$r, (SPlo tconstpool:$in)), (ADDXri $r, tconstpool:$in)>; ++def : Pat<(add iPTR:$r, (SPlo tblockaddress:$in)), ++ (ADDXri $r, tblockaddress:$in)>; ++} +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -210,15 +210,16 @@ def FCC_O : FCC_VAL<29>; // Ordered + //===----------------------------------------------------------------------===// + + /// F3_12 multiclass - Define a normal F3_1/F3_2 pattern in one shot. +-multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode> { ++multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode, ++ RegisterClass RC, ValueType Ty, Operand immOp> { + def rr : F3_1<2, Op3Val, +- (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), ++ (outs RC:$dst), (ins RC:$b, RC:$c), + !strconcat(OpcStr, " $b, $c, $dst"), +- [(set i32:$dst, (OpNode i32:$b, i32:$c))]>; ++ [(set Ty:$dst, (OpNode Ty:$b, Ty:$c))]>; + def ri : F3_2<2, Op3Val, +- (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), ++ (outs RC:$dst), (ins RC:$b, immOp:$c), + !strconcat(OpcStr, " $b, $c, $dst"), +- [(set i32:$dst, (OpNode i32:$b, (i32 simm13:$c)))]>; ++ [(set Ty:$dst, (OpNode Ty:$b, (Ty simm13:$c)))]>; + } + + /// F3_12np multiclass - Define a normal F3_1/F3_2 pattern in one shot, with no +@@ -464,7 +465,7 @@ let rd = 0, imm22 = 0 in + def NOP : F2_1<0b100, (outs), (ins), "nop", []>; + + // Section B.11 - Logical Instructions, p. 106 +-defm AND : F3_12<"and", 0b000001, and>; ++defm AND : F3_12<"and", 0b000001, and, IntRegs, i32, i32imm>; + + def ANDNrr : F3_1<2, 0b000101, + (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), +@@ -474,7 +475,7 @@ def ANDNri : F3_2<2, 0b000101, + (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), + "andn $b, $c, $dst", []>; + +-defm OR : F3_12<"or", 0b000010, or>; ++defm OR : F3_12<"or", 0b000010, or, IntRegs, i32, i32imm>; + + def ORNrr : F3_1<2, 0b000110, + (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), +@@ -483,7 +484,7 @@ def ORNrr : F3_1<2, 0b000110, + def ORNri : F3_2<2, 0b000110, + (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), + "orn $b, $c, $dst", []>; +-defm XOR : F3_12<"xor", 0b000011, xor>; ++defm XOR : F3_12<"xor", 0b000011, xor, IntRegs, i32, i32imm>; + + def XNORrr : F3_1<2, 0b000111, + (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), +@@ -494,12 +495,12 @@ def XNORri : F3_2<2, 0b000111, + "xnor $b, $c, $dst", []>; + + // Section B.12 - Shift Instructions, p. 107 +-defm SLL : F3_12<"sll", 0b100101, shl>; +-defm SRL : F3_12<"srl", 0b100110, srl>; +-defm SRA : F3_12<"sra", 0b100111, sra>; ++defm SLL : F3_12<"sll", 0b100101, shl, IntRegs, i32, i32imm>; ++defm SRL : F3_12<"srl", 0b100110, srl, IntRegs, i32, i32imm>; ++defm SRA : F3_12<"sra", 0b100111, sra, IntRegs, i32, i32imm>; + + // Section B.13 - Add Instructions, p. 108 +-defm ADD : F3_12<"add", 0b000000, add>; ++defm ADD : F3_12<"add", 0b000000, add, IntRegs, i32, i32imm>; + + // "LEA" forms of add (patterns to make tblgen happy) + let Predicates = [Is32Bit] in +@@ -509,18 +510,18 @@ let Predicates = [Is32Bit] in + [(set iPTR:$dst, ADDRri:$addr)]>; + + let Defs = [ICC] in +- defm ADDCC : F3_12<"addcc", 0b010000, addc>; ++ defm ADDCC : F3_12<"addcc", 0b010000, addc, IntRegs, i32, i32imm>; + + let Uses = [ICC], Defs = [ICC] in +- defm ADDX : F3_12<"addxcc", 0b011000, adde>; ++ defm ADDE : F3_12<"addxcc", 0b011000, adde, IntRegs, i32, i32imm>; + + // Section B.15 - Subtract Instructions, p. 110 +-defm SUB : F3_12 <"sub" , 0b000100, sub>; ++defm SUB : F3_12 <"sub" , 0b000100, sub, IntRegs, i32, i32imm>; + let Uses = [ICC], Defs = [ICC] in +- defm SUBX : F3_12 <"subxcc" , 0b011100, sube>; ++ defm SUBE : F3_12 <"subxcc" , 0b011100, sube, IntRegs, i32, i32imm>; + + let Defs = [ICC] in +- defm SUBCC : F3_12 <"subcc", 0b010100, subc>; ++ defm SUBCC : F3_12 <"subcc", 0b010100, subc, IntRegs, i32, i32imm>; + + let Defs = [ICC], rd = 0 in { + def CMPrr : F3_1<2, 0b010100, +@@ -542,7 +543,7 @@ let Uses = [ICC], Defs = [ICC] in + // Section B.18 - Multiply Instructions, p. 113 + let Defs = [Y] in { + defm UMUL : F3_12np<"umul", 0b001010>; +- defm SMUL : F3_12 <"smul", 0b001011, mul>; ++ defm SMUL : F3_12 <"smul", 0b001011, mul, IntRegs, i32, i32imm>; + } + + // Section B.19 - Divide Instructions, p. 115 +@@ -987,6 +988,8 @@ def : Pat<(i32 imm:$val), + + + // Global addresses, constant pool entries ++let Predicates = [Is32Bit] in { ++ + def : Pat<(SPhi tglobaladdr:$in), (SETHIi tglobaladdr:$in)>; + def : Pat<(SPlo tglobaladdr:$in), (ORri (i32 G0), tglobaladdr:$in)>; + def : Pat<(SPhi tconstpool:$in), (SETHIi tconstpool:$in)>; +@@ -1009,6 +1012,7 @@ def : Pat<(add iPTR:$r, (SPlo tglobaladdr:$in)), ( + def : Pat<(add iPTR:$r, (SPlo tconstpool:$in)), (ADDri $r, tconstpool:$in)>; + def : Pat<(add iPTR:$r, (SPlo tblockaddress:$in)), + (ADDri $r, tblockaddress:$in)>; ++} + + // Calls: + def : Pat<(call tglobaladdr:$dst), +Index: test/CodeGen/SPARC/64spill.ll +=================================================================== +--- test/CodeGen/SPARC/64spill.ll ++++ test/CodeGen/SPARC/64spill.ll +@@ -0,0 +1,116 @@ ++; RUN: llc < %s -march=sparcv9 | FileCheck %s ++ ++target datalayout = "E-i64:64-n32:64-S128" ++target triple = "sparc64-sun-sparc" ++ ++; CHECK-LABEL: test_and_spill ++; CHECK: and %i0, %i1, [[R:%[gilo][0-7]]] ++; CHECK: stx [[R]], [%fp+{{.+}}] ++; CHECK: ldx [%fp+{{.+}}, %i0 ++define i64 @test_and_spill(i64 %a, i64 %b) { ++entry: ++ %r0 = and i64 %a, %b ++ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0) ++ ret i64 %r0 ++} ++ ++; CHECK-LABEL: test_or_spill ++; CHECK: or %i0, %i1, [[R:%[gilo][0-7]]] ++; CHECK: stx [[R]], [%fp+{{.+}}] ++; CHECK: ldx [%fp+{{.+}}, %i0 ++define i64 @test_or_spill(i64 %a, i64 %b) { ++entry: ++ %r0 = or i64 %a, %b ++ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0) ++ ret i64 %r0 ++} ++ ++; CHECK-LABEL: test_xor_spill ++; CHECK: xor %i0, %i1, [[R:%[gilo][0-7]]] ++; CHECK: stx [[R]], [%fp+{{.+}}] ++; CHECK: ldx [%fp+{{.+}}, %i0 ++define i64 @test_xor_spill(i64 %a, i64 %b) { ++entry: ++ %r0 = xor i64 %a, %b ++ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0) ++ ret i64 %r0 ++} ++ ++ ++; CHECK-LABEL: test_add_spill ++; CHECK: add %i0, %i1, [[R:%[gilo][0-7]]] ++; CHECK: stx [[R]], [%fp+{{.+}}] ++; CHECK: ldx [%fp+{{.+}}, %i0 ++define i64 @test_add_spill(i64 %a, i64 %b) { ++entry: ++ %r0 = add i64 %a, %b ++ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0) ++ ret i64 %r0 ++} ++ ++; CHECK-LABEL: test_sub_spill ++; CHECK: sub %i0, %i1, [[R:%[gilo][0-7]]] ++; CHECK: stx [[R]], [%fp+{{.+}}] ++; CHECK: ldx [%fp+{{.+}}, %i0 ++define i64 @test_sub_spill(i64 %a, i64 %b) { ++entry: ++ %r0 = sub i64 %a, %b ++ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0) ++ ret i64 %r0 ++} ++ ++; CHECK-LABEL: test_andi_spill ++; CHECK: and %i0, 1729, [[R:%[gilo][0-7]]] ++; CHECK: stx [[R]], [%fp+{{.+}}] ++; CHECK: ldx [%fp+{{.+}}, %i0 ++define i64 @test_andi_spill(i64 %a) { ++entry: ++ %r0 = and i64 %a, 1729 ++ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0) ++ ret i64 %r0 ++} ++ ++; CHECK-LABEL: test_ori_spill ++; CHECK: or %i0, 1729, [[R:%[gilo][0-7]]] ++; CHECK: stx [[R]], [%fp+{{.+}}] ++; CHECK: ldx [%fp+{{.+}}, %i0 ++define i64 @test_ori_spill(i64 %a) { ++entry: ++ %r0 = or i64 %a, 1729 ++ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0) ++ ret i64 %r0 ++} ++ ++; CHECK-LABEL: test_xori_spill ++; CHECK: xor %i0, 1729, [[R:%[gilo][0-7]]] ++; CHECK: stx [[R]], [%fp+{{.+}}] ++; CHECK: ldx [%fp+{{.+}}, %i0 ++define i64 @test_xori_spill(i64 %a) { ++entry: ++ %r0 = xor i64 %a, 1729 ++ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0) ++ ret i64 %r0 ++} ++ ++; CHECK-LABEL: test_addi_spill ++; CHECK: add %i0, 1729, [[R:%[gilo][0-7]]] ++; CHECK: stx [[R]], [%fp+{{.+}}] ++; CHECK: ldx [%fp+{{.+}}, %i0 ++define i64 @test_addi_spill(i64 %a) { ++entry: ++ %r0 = add i64 %a, 1729 ++ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0) ++ ret i64 %r0 ++} ++ ++; CHECK-LABEL: test_subi_spill ++; CHECK: add %i0, -1729, [[R:%[gilo][0-7]]] ++; CHECK: stx [[R]], [%fp+{{.+}}] ++; CHECK: ldx [%fp+{{.+}}, %i0 ++define i64 @test_subi_spill(i64 %a) { ++entry: ++ %r0 = sub i64 %a, 1729 ++ %0 = tail call i64 asm sideeffect "#$0 $1", "=r,r,~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{g1},~{g2},~{g3},~{g4},~{g5},~{g6},~{g7},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6}"(i64 %r0) ++ ret i64 %r0 ++} ++ diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198280-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198280-sparc.diff new file mode 100644 index 0000000..f75d9fc --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198280-sparc.diff @@ -0,0 +1,55 @@ +Pull in r198280 from upstream llvm trunk (by Venkatraman Govindaraju): + + [SparcV9]: Use SRL instead of SLL to clear top 32-bits in ctpop:i32. SLL does not clear top 32 bit, only SRL does. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -967,13 +967,13 @@ let Predicates = [HasV9] in { + } + + // POPCrr - This does a ctpop of a 64-bit register. As such, we have to clear +-// the top 32-bits before using it. To do this clearing, we use a SLLri X,0. ++// the top 32-bits before using it. To do this clearing, we use a SRLri X,0. + let rs1 = 0 in + def POPCrr : F3_1<2, 0b101110, + (outs IntRegs:$dst), (ins IntRegs:$src), + "popc $src, $dst", []>, Requires<[HasV9]>; + def : Pat<(ctpop i32:$src), +- (POPCrr (SLLri $src, 0))>; ++ (POPCrr (SRLri $src, 0))>; + + //===----------------------------------------------------------------------===// + // Non-Instruction Patterns +Index: test/CodeGen/SPARC/ctpop.ll +=================================================================== +--- test/CodeGen/SPARC/ctpop.ll ++++ test/CodeGen/SPARC/ctpop.ll +@@ -1,8 +1,22 @@ +-; RUN: llc < %s -march=sparc -mattr=-v9 | not grep popc +-; RUN: llc < %s -march=sparc -mattr=+v9 | grep popc ++; RUN: llc < %s -march=sparc -mattr=-v9 | FileCheck %s -check-prefix=V8 ++; RUN: llc < %s -march=sparc -mattr=+v9 | FileCheck %s -check-prefix=V9 ++; RUN: llc < %s -march=sparcv9 | FileCheck %s -check-prefix=SPARC64 + + declare i32 @llvm.ctpop.i32(i32) + ++; V8-LABEL: test ++; V8-NOT : popc ++ ++; V9-LABEL: test ++; V9: srl %o0, 0, %o0 ++; V9-NEXT: jmp %o7+8 ++; V9-NEXT: popc %o0, %o0 ++ ++; SPARC64-LABEL: test ++; SPARC64: srl %o0, 0, %o0 ++; SPARC64: jmp %o7+8 ++; SPARC64: popc %o0, %o0 ++ + define i32 @test(i32 %X) { + %Y = call i32 @llvm.ctpop.i32( i32 %X ) ; <i32> [#uses=1] + ret i32 %Y diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198281-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198281-sparc.diff new file mode 100644 index 0000000..0af21f4 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198281-sparc.diff @@ -0,0 +1,99 @@ +Pull in r198281 from upstream llvm trunk (by Venkatraman Govindaraju): + + [SparcV9]: Custom lower UMULO/SMULO so that the arguments are send to __multi3() in correct order. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -1525,6 +1525,9 @@ SparcTargetLowering::SparcTargetLowering(TargetMac + setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand); + setOperationAction(ISD::MULHU, MVT::i64, Expand); + setOperationAction(ISD::MULHS, MVT::i64, Expand); ++ ++ setOperationAction(ISD::UMULO, MVT::i64, Custom); ++ setOperationAction(ISD::SMULO, MVT::i64, Custom); + } + + // VASTART needs to be custom lowered to use the VarArgsFrameIndex. +@@ -2673,6 +2676,53 @@ static SDValue LowerADDC_ADDE_SUBC_SUBE(SDValue Op + return DAG.getMergeValues(Ops, 2, dl); + } + ++// Custom lower UMULO/SMULO for SPARC. This code is similar to ExpandNode() ++// in LegalizeDAG.cpp except the order of arguments to the library function. ++static SDValue LowerUMULO_SMULO(SDValue Op, SelectionDAG &DAG, ++ const SparcTargetLowering &TLI) ++{ ++ unsigned opcode = Op.getOpcode(); ++ assert((opcode == ISD::UMULO || opcode == ISD::SMULO) && "Invalid Opcode."); ++ ++ bool isSigned = (opcode == ISD::SMULO); ++ EVT VT = MVT::i64; ++ EVT WideVT = MVT::i128; ++ SDLoc dl(Op); ++ SDValue LHS = Op.getOperand(0); ++ ++ if (LHS.getValueType() != VT) ++ return Op; ++ ++ SDValue ShiftAmt = DAG.getConstant(63, VT); ++ ++ SDValue RHS = Op.getOperand(1); ++ SDValue HiLHS = DAG.getNode(ISD::SRA, dl, VT, LHS, ShiftAmt); ++ SDValue HiRHS = DAG.getNode(ISD::SRA, dl, MVT::i64, RHS, ShiftAmt); ++ SDValue Args[] = { HiLHS, LHS, HiRHS, RHS }; ++ ++ SDValue MulResult = TLI.makeLibCall(DAG, ++ RTLIB::MUL_I128, WideVT, ++ Args, 4, isSigned, dl).first; ++ SDValue BottomHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, ++ MulResult, DAG.getIntPtrConstant(0)); ++ SDValue TopHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, ++ MulResult, DAG.getIntPtrConstant(1)); ++ if (isSigned) { ++ SDValue Tmp1 = DAG.getNode(ISD::SRA, dl, VT, BottomHalf, ShiftAmt); ++ TopHalf = DAG.getSetCC(dl, MVT::i32, TopHalf, Tmp1, ISD::SETNE); ++ } else { ++ TopHalf = DAG.getSetCC(dl, MVT::i32, TopHalf, DAG.getConstant(0, VT), ++ ISD::SETNE); ++ } ++ // MulResult is a node with an illegal type. Because such things are not ++ // generally permitted during this phase of legalization, delete the ++ // node. The above EXTRACT_ELEMENT nodes should have been folded. ++ DAG.DeleteNode(MulResult.getNode()); ++ ++ SDValue Ops[2] = { BottomHalf, TopHalf } ; ++ return DAG.getMergeValues(Ops, 2, dl); ++} ++ + SDValue SparcTargetLowering:: + LowerOperation(SDValue Op, SelectionDAG &DAG) const { + +@@ -2726,6 +2776,8 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) cons + case ISD::ADDE: + case ISD::SUBC: + case ISD::SUBE: return LowerADDC_ADDE_SUBC_SUBE(Op, DAG); ++ case ISD::UMULO: ++ case ISD::SMULO: return LowerUMULO_SMULO(Op, DAG, *this); + } + } + +Index: test/CodeGen/SPARC/64cond.ll +=================================================================== +--- test/CodeGen/SPARC/64cond.ll ++++ test/CodeGen/SPARC/64cond.ll +@@ -111,6 +111,11 @@ entry: + } + + ; CHECK-LABEL: setcc_resultty ++; CHECK-DAG: srax %i0, 63, %o0 ++; CHECK-DAG: or %g0, %i0, %o1 ++; CHECK-DAG: or %g0, 0, %o2 ++; CHECK-DAG: or %g0, 32, %o3 ++; CHECK-DAG: call __multi3 + ; CHECK: cmp + ; CHECK: movne %xcc, 1, [[R:%[gilo][0-7]]] + ; CHECK: or [[R]], %i1, %i0 diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198286-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198286-sparc.diff new file mode 100644 index 0000000..041e263 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198286-sparc.diff @@ -0,0 +1,231 @@ +Pull in r198286 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Handle atomic loads/stores in sparc backend. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -975,6 +975,33 @@ let rs1 = 0 in + def : Pat<(ctpop i32:$src), + (POPCrr (SRLri $src, 0))>; + ++// Atomic swap. ++let hasSideEffects =1, rd = 0, rs1 = 0b01111, rs2 = 0 in ++ def STBAR : F3_1<2, 0b101000, (outs), (ins), "stbar", []>; ++ ++let Predicates = [HasV9], hasSideEffects = 1, rd = 0, rs1 = 0b01111 in ++ def MEMBARi : F3_2<2, 0b101000, (outs), (ins i32imm:$simm13), ++ "membar $simm13", []>; ++ ++let Constraints = "$val = $rd" in { ++ def SWAPrr : F3_1<3, 0b001111, ++ (outs IntRegs:$rd), (ins IntRegs:$val, MEMrr:$addr), ++ "swap [$addr], $rd", ++ [(set i32:$rd, (atomic_swap_32 ADDRrr:$addr, i32:$val))]>; ++ def SWAPri : F3_2<3, 0b001111, ++ (outs IntRegs:$rd), (ins IntRegs:$val, MEMri:$addr), ++ "swap [$addr], $rd", ++ [(set i32:$rd, (atomic_swap_32 ADDRri:$addr, i32:$val))]>; ++} ++ ++let Predicates = [HasV9], Constraints = "$swap = $rd" in ++ def CASrr: F3_1<3, 0b111100, ++ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, ++ IntRegs:$swap), ++ "cas [$rs1], $rs2, $rd", ++ [(set i32:$rd, ++ (atomic_cmp_swap iPTR:$rs1, i32:$rs2, i32:$swap))]>; ++ + //===----------------------------------------------------------------------===// + // Non-Instruction Patterns + //===----------------------------------------------------------------------===// +@@ -1036,4 +1063,17 @@ def : Pat<(i32 (zextloadi1 ADDRri:$src)), (LDUBri + def : Pat<(store (i32 0), ADDRrr:$dst), (STrr ADDRrr:$dst, (i32 G0))>; + def : Pat<(store (i32 0), ADDRri:$dst), (STri ADDRri:$dst, (i32 G0))>; + ++// store bar for all atomic_fence in V8. ++let Predicates = [HasNoV9] in ++ def : Pat<(atomic_fence imm, imm), (STBAR)>; ++ ++// atomic_load_32 addr -> load addr ++def : Pat<(i32 (atomic_load ADDRrr:$src)), (LDrr ADDRrr:$src)>; ++def : Pat<(i32 (atomic_load ADDRri:$src)), (LDri ADDRri:$src)>; ++ ++// atomic_store_32 val, addr -> store val, addr ++def : Pat<(atomic_store ADDRrr:$dst, i32:$val), (STrr ADDRrr:$dst, $val)>; ++def : Pat<(atomic_store ADDRri:$dst, i32:$val), (STri ADDRri:$dst, $val)>; ++ ++ + include "SparcInstr64Bit.td" +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -1472,10 +1472,30 @@ SparcTargetLowering::SparcTargetLowering(TargetMac + setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom); + } + +- // FIXME: There are instructions available for ATOMIC_FENCE +- // on SparcV8 and later. +- setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand); ++ // ATOMICs. ++ // FIXME: We insert fences for each atomics and generate sub-optimal code ++ // for PSO/TSO. Also, implement other atomicrmw operations. + ++ setInsertFencesForAtomic(true); ++ ++ setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, Legal); ++ setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, ++ (Subtarget->isV9() ? Legal: Expand)); ++ ++ ++ setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Legal); ++ ++ // Custom Lower Atomic LOAD/STORE ++ setOperationAction(ISD::ATOMIC_LOAD, MVT::i32, Custom); ++ setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Custom); ++ ++ if (Subtarget->is64Bit()) { ++ setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i64, Legal); ++ setOperationAction(ISD::ATOMIC_SWAP, MVT::i64, Expand); ++ setOperationAction(ISD::ATOMIC_LOAD, MVT::i64, Custom); ++ setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Custom); ++ } ++ + if (!Subtarget->isV9()) { + // SparcV8 does not have FNEGD and FABSD. + setOperationAction(ISD::FNEG, MVT::f64, Custom); +@@ -2723,6 +2743,16 @@ static SDValue LowerUMULO_SMULO(SDValue Op, Select + return DAG.getMergeValues(Ops, 2, dl); + } + ++static SDValue LowerATOMIC_LOAD_STORE(SDValue Op, SelectionDAG &DAG) { ++ // Monotonic load/stores are legal. ++ if (cast<AtomicSDNode>(Op)->getOrdering() <= Monotonic) ++ return Op; ++ ++ // Otherwise, expand with a fence. ++ return SDValue(); ++} ++ ++ + SDValue SparcTargetLowering:: + LowerOperation(SDValue Op, SelectionDAG &DAG) const { + +@@ -2778,6 +2808,8 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) cons + case ISD::SUBE: return LowerADDC_ADDE_SUBC_SUBE(Op, DAG); + case ISD::UMULO: + case ISD::SMULO: return LowerUMULO_SMULO(Op, DAG, *this); ++ case ISD::ATOMIC_LOAD: ++ case ISD::ATOMIC_STORE: return LowerATOMIC_LOAD_STORE(Op, DAG); + } + } + +Index: lib/Target/Sparc/SparcInstr64Bit.td +=================================================================== +--- lib/Target/Sparc/SparcInstr64Bit.td ++++ lib/Target/Sparc/SparcInstr64Bit.td +@@ -415,6 +415,32 @@ def SETHIXi : F2_1<0b100, + "sethi $imm22, $rd", + [(set i64:$rd, SETHIimm:$imm22)]>; + } ++ ++// ATOMICS. ++let Predicates = [Is64Bit], Constraints = "$swap = $rd" in { ++ def CASXrr: F3_1<3, 0b111110, ++ (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2, ++ I64Regs:$swap), ++ "casx [$rs1], $rs2, $rd", ++ [(set i64:$rd, ++ (atomic_cmp_swap i64:$rs1, i64:$rs2, i64:$swap))]>; ++ ++} // Predicates = [Is64Bit], Constraints = ... ++ ++let Predicates = [Is64Bit] in { ++ ++def : Pat<(atomic_fence imm, imm), (MEMBARi 0xf)>; ++ ++// atomic_load_64 addr -> load addr ++def : Pat<(i64 (atomic_load ADDRrr:$src)), (LDXrr ADDRrr:$src)>; ++def : Pat<(i64 (atomic_load ADDRri:$src)), (LDXri ADDRri:$src)>; ++ ++// atomic_store_64 val, addr -> store val, addr ++def : Pat<(atomic_store ADDRrr:$dst, i64:$val), (STXrr ADDRrr:$dst, $val)>; ++def : Pat<(atomic_store ADDRri:$dst, i64:$val), (STXri ADDRri:$dst, $val)>; ++ ++} // Predicates = [Is64Bit] ++ + // Global addresses, constant pool entries + let Predicates = [Is64Bit] in { + +Index: test/CodeGen/SPARC/atomics.ll +=================================================================== +--- test/CodeGen/SPARC/atomics.ll ++++ test/CodeGen/SPARC/atomics.ll +@@ -0,0 +1,63 @@ ++; RUN: llc < %s -march=sparcv9 | FileCheck %s ++ ++; CHECK-LABEL: test_atomic_i32 ++; CHECK: ld [%o0] ++; CHECK: membar ++; CHECK: ld [%o1] ++; CHECK: membar ++; CHECK: membar ++; CHECK: st {{.+}}, [%o2] ++define i32 @test_atomic_i32(i32* %ptr1, i32* %ptr2, i32* %ptr3) { ++entry: ++ %0 = load atomic i32* %ptr1 acquire, align 8 ++ %1 = load atomic i32* %ptr2 acquire, align 8 ++ %2 = add i32 %0, %1 ++ store atomic i32 %2, i32* %ptr3 release, align 8 ++ ret i32 %2 ++} ++ ++; CHECK-LABEL: test_atomic_i64 ++; CHECK: ldx [%o0] ++; CHECK: membar ++; CHECK: ldx [%o1] ++; CHECK: membar ++; CHECK: membar ++; CHECK: stx {{.+}}, [%o2] ++define i64 @test_atomic_i64(i64* %ptr1, i64* %ptr2, i64* %ptr3) { ++entry: ++ %0 = load atomic i64* %ptr1 acquire, align 8 ++ %1 = load atomic i64* %ptr2 acquire, align 8 ++ %2 = add i64 %0, %1 ++ store atomic i64 %2, i64* %ptr3 release, align 8 ++ ret i64 %2 ++} ++ ++; CHECK-LABEL: test_cmpxchg_i32 ++; CHECK: or %g0, 123, [[R:%[gilo][0-7]]] ++; CHECK: cas [%o1], %o0, [[R]] ++ ++define i32 @test_cmpxchg_i32(i32 %a, i32* %ptr) { ++entry: ++ %b = cmpxchg i32* %ptr, i32 %a, i32 123 monotonic ++ ret i32 %b ++} ++ ++; CHECK-LABEL: test_cmpxchg_i64 ++; CHECK: or %g0, 123, [[R:%[gilo][0-7]]] ++; CHECK: casx [%o1], %o0, [[R]] ++ ++define i64 @test_cmpxchg_i64(i64 %a, i64* %ptr) { ++entry: ++ %b = cmpxchg i64* %ptr, i64 %a, i64 123 monotonic ++ ret i64 %b ++} ++ ++; CHECK-LABEL: test_swap_i32 ++; CHECK: or %g0, 42, [[R:%[gilo][0-7]]] ++; CHECK: swap [%o1], [[R]] ++ ++define i32 @test_swap_i32(i32 %a, i32* %ptr) { ++entry: ++ %b = atomicrmw xchg i32* %ptr, i32 42 monotonic ++ ret i32 %b ++} diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198480-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198480-sparc.diff new file mode 100644 index 0000000..b3e1362 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198480-sparc.diff @@ -0,0 +1,213 @@ +Pull in r198480 from upstream llvm trunk (by Venkatraman Govindaraju): + + [SparcV9]: Implement RETURNADDR and FRAMEADDR lowering in SPARC64. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -2415,7 +2415,8 @@ static SDValue getFLUSHW(SDValue Op, SelectionDAG + return Chain; + } + +-static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) { ++static SDValue getFRAMEADDR(uint64_t depth, SDValue Op, SelectionDAG &DAG, ++ const SparcSubtarget *Subtarget) { + MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); + MFI->setFrameAddressIsTaken(true); + +@@ -2422,32 +2423,49 @@ static SDValue getFLUSHW(SDValue Op, SelectionDAG + EVT VT = Op.getValueType(); + SDLoc dl(Op); + unsigned FrameReg = SP::I6; ++ unsigned stackBias = Subtarget->getStackPointerBias(); + +- uint64_t depth = Op.getConstantOperandVal(0); ++ SDValue FrameAddr; + +- SDValue FrameAddr; +- if (depth == 0) ++ if (depth == 0) { + FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT); +- else { +- // flush first to make sure the windowed registers' values are in stack +- SDValue Chain = getFLUSHW(Op, DAG); +- FrameAddr = DAG.getCopyFromReg(Chain, dl, FrameReg, VT); ++ if (Subtarget->is64Bit()) ++ FrameAddr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr, ++ DAG.getIntPtrConstant(stackBias)); ++ return FrameAddr; ++ } + +- for (uint64_t i = 0; i != depth; ++i) { +- SDValue Ptr = DAG.getNode(ISD::ADD, +- dl, MVT::i32, +- FrameAddr, DAG.getIntPtrConstant(56)); +- FrameAddr = DAG.getLoad(MVT::i32, dl, +- Chain, +- Ptr, +- MachinePointerInfo(), false, false, false, 0); +- } ++ // flush first to make sure the windowed registers' values are in stack ++ SDValue Chain = getFLUSHW(Op, DAG); ++ FrameAddr = DAG.getCopyFromReg(Chain, dl, FrameReg, VT); ++ ++ unsigned Offset = (Subtarget->is64Bit()) ? (stackBias + 112) : 56; ++ ++ while (depth--) { ++ SDValue Ptr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr, ++ DAG.getIntPtrConstant(Offset)); ++ FrameAddr = DAG.getLoad(VT, dl, Chain, Ptr, MachinePointerInfo(), ++ false, false, false, 0); + } ++ if (Subtarget->is64Bit()) ++ FrameAddr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr, ++ DAG.getIntPtrConstant(stackBias)); + return FrameAddr; + } + ++ ++static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG, ++ const SparcSubtarget *Subtarget) { ++ ++ uint64_t depth = Op.getConstantOperandVal(0); ++ ++ return getFRAMEADDR(depth, Op, DAG, Subtarget); ++ ++} ++ + static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG, +- const SparcTargetLowering &TLI) { ++ const SparcTargetLowering &TLI, ++ const SparcSubtarget *Subtarget) { + MachineFunction &MF = DAG.getMachineFunction(); + MachineFrameInfo *MFI = MF.getFrameInfo(); + MFI->setReturnAddressIsTaken(true); +@@ -2461,25 +2479,20 @@ static SDValue LowerRETURNADDR(SDValue Op, Selecti + unsigned RetReg = MF.addLiveIn(SP::I7, + TLI.getRegClassFor(TLI.getPointerTy())); + RetAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, RetReg, VT); +- } else { +- // Need frame address to find return address of the caller. +- MFI->setFrameAddressIsTaken(true); ++ return RetAddr; ++ } + +- // flush first to make sure the windowed registers' values are in stack +- SDValue Chain = getFLUSHW(Op, DAG); +- RetAddr = DAG.getCopyFromReg(Chain, dl, SP::I6, VT); ++ // Need frame address to find return address of the caller. ++ SDValue FrameAddr = getFRAMEADDR(depth - 1, Op, DAG, Subtarget); + +- for (uint64_t i = 0; i != depth; ++i) { +- SDValue Ptr = DAG.getNode(ISD::ADD, +- dl, MVT::i32, +- RetAddr, +- DAG.getIntPtrConstant((i == depth-1)?60:56)); +- RetAddr = DAG.getLoad(MVT::i32, dl, +- Chain, +- Ptr, +- MachinePointerInfo(), false, false, false, 0); +- } +- } ++ unsigned Offset = (Subtarget->is64Bit()) ? 120 : 60; ++ SDValue Ptr = DAG.getNode(ISD::ADD, ++ dl, VT, ++ FrameAddr, ++ DAG.getIntPtrConstant(Offset)); ++ RetAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), Ptr, ++ MachinePointerInfo(), false, false, false, 0); ++ + return RetAddr; + } + +@@ -2763,8 +2776,10 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) cons + switch (Op.getOpcode()) { + default: llvm_unreachable("Should not custom lower this!"); + +- case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG, *this); +- case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); ++ case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG, *this, ++ Subtarget); ++ case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG, ++ Subtarget); + case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG); + case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); + case ISD::BlockAddress: return LowerBlockAddress(Op, DAG); +Index: test/CodeGen/SPARC/2011-01-11-FrameAddr.ll +=================================================================== +--- test/CodeGen/SPARC/2011-01-11-FrameAddr.ll ++++ test/CodeGen/SPARC/2011-01-11-FrameAddr.ll +@@ -2,6 +2,7 @@ + ;RUN: llc -march=sparc -mattr=v9 < %s | FileCheck %s -check-prefix=V9 + ;RUN: llc -march=sparc -regalloc=basic < %s | FileCheck %s -check-prefix=V8 + ;RUN: llc -march=sparc -regalloc=basic -mattr=v9 < %s | FileCheck %s -check-prefix=V9 ++;RUN: llc -march=sparcv9 < %s | FileCheck %s -check-prefix=SPARC64 + + + define i8* @frameaddr() nounwind readnone { +@@ -15,6 +16,13 @@ entry: + ;V9: save %sp, -96, %sp + ;V9: jmp %i7+8 + ;V9: restore %g0, %fp, %o0 ++ ++;SPARC64-LABEL: frameaddr ++;SPARC64: save %sp, -128, %sp ++;SPARC64: add %fp, 2047, %i0 ++;SPARC64: jmp %i7+8 ++;SPARC64: restore %g0, %g0, %g0 ++ + %0 = tail call i8* @llvm.frameaddress(i32 0) + ret i8* %0 + } +@@ -32,6 +40,14 @@ entry: + ;V9: ld [%fp+56], {{.+}} + ;V9: ld [{{.+}}+56], {{.+}} + ;V9: ld [{{.+}}+56], {{.+}} ++ ++;SPARC64-LABEL: frameaddr2 ++;SPARC64: flushw ++;SPARC64: ldx [%fp+2159], %[[R0:[goli][0-7]]] ++;SPARC64: ldx [%[[R0]]+2159], %[[R1:[goli][0-7]]] ++;SPARC64: ldx [%[[R1]]+2159], %[[R2:[goli][0-7]]] ++;SPARC64: add %[[R2]], 2047, {{.+}} ++ + %0 = tail call i8* @llvm.frameaddress(i32 3) + ret i8* %0 + } +@@ -48,6 +64,9 @@ entry: + ;V9-LABEL: retaddr: + ;V9: or %g0, %o7, {{.+}} + ++;SPARC64-LABEL: retaddr ++;SPARC64: or %g0, %o7, {{.+}} ++ + %0 = tail call i8* @llvm.returnaddress(i32 0) + ret i8* %0 + } +@@ -66,18 +85,12 @@ entry: + ;V9: ld [{{.+}}+56], {{.+}} + ;V9: ld [{{.+}}+60], {{.+}} + +-;V8LEAF-LABEL: retaddr2: +-;V8LEAF: ta 3 +-;V8LEAF: ld [%fp+56], %[[R:[goli][0-7]]] +-;V8LEAF: ld [%[[R]]+56], %[[R1:[goli][0-7]]] +-;V8LEAF: ld [%[[R1]]+60], {{.+}} ++;SPARC64-LABEL: retaddr2 ++;SPARC64: flushw ++;SPARC64: ldx [%fp+2159], %[[R0:[goli][0-7]]] ++;SPARC64: ldx [%[[R0]]+2159], %[[R1:[goli][0-7]]] ++;SPARC64: ldx [%[[R1]]+2167], {{.+}} + +-;V9LEAF-LABEL: retaddr2: +-;V9LEAF: flushw +-;V9LEAF: ld [%fp+56], %[[R:[goli][0-7]]] +-;V9LEAF: ld [%[[R]]+56], %[[R1:[goli][0-7]]] +-;V9LEAF: ld [%[[R1]]+60], {{.+}} +- + %0 = tail call i8* @llvm.returnaddress(i32 3) + ret i8* %0 + } diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198484-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198484-sparc.diff new file mode 100644 index 0000000..3bfb7d5 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198484-sparc.diff @@ -0,0 +1,844 @@ +Pull in r198484 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add the initial implementation of an asm parser for sparc/sparcv9. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +@@ -123,13 +123,18 @@ extern "C" void LLVMInitializeSparcTargetMC() { + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(TheSparcTarget, createSparcMCInstrInfo); ++ TargetRegistry::RegisterMCInstrInfo(TheSparcV9Target, createSparcMCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(TheSparcTarget, createSparcMCRegisterInfo); ++ TargetRegistry::RegisterMCRegInfo(TheSparcV9Target, ++ createSparcMCRegisterInfo); + + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(TheSparcTarget, + createSparcMCSubtargetInfo); ++ TargetRegistry::RegisterMCSubtargetInfo(TheSparcV9Target, ++ createSparcMCSubtargetInfo); + + TargetRegistry::RegisterAsmStreamer(TheSparcTarget, + createMCAsmStreamer); +Index: lib/Target/Sparc/LLVMBuild.txt +=================================================================== +--- lib/Target/Sparc/LLVMBuild.txt ++++ lib/Target/Sparc/LLVMBuild.txt +@@ -16,7 +16,7 @@ + ;===------------------------------------------------------------------------===; + + [common] +-subdirectories = InstPrinter MCTargetDesc TargetInfo ++subdirectories = AsmParser InstPrinter MCTargetDesc TargetInfo + + [component_0] + type = TargetGroup +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -76,13 +76,25 @@ def ADDRrr : ComplexPattern<iPTR, 2, "SelectADDRrr + def ADDRri : ComplexPattern<iPTR, 2, "SelectADDRri", [frameindex], []>; + + // Address operands ++def SparcMEMrrAsmOperand : AsmOperandClass { ++ let Name = "MEMrr"; ++ let ParserMethod = "parseMEMrrOperand"; ++} ++ ++def SparcMEMriAsmOperand : AsmOperandClass { ++ let Name = "MEMri"; ++ let ParserMethod = "parseMEMriOperand"; ++} ++ + def MEMrr : Operand<iPTR> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops ptr_rc, ptr_rc); ++ let ParserMatchClass = SparcMEMrrAsmOperand; + } + def MEMri : Operand<iPTR> { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops ptr_rc, i32imm); ++ let ParserMatchClass = SparcMEMriAsmOperand; + } + + def TLSSym : Operand<iPTR>; +@@ -239,7 +251,10 @@ multiclass F3_12np<string OpcStr, bits<6> Op3Val> + + // Pseudo instructions. + class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern> +- : InstSP<outs, ins, asmstr, pattern>; ++ : InstSP<outs, ins, asmstr, pattern> { ++ let isCodeGenOnly = 1; ++ let isPseudo = 1; ++} + + // GETPCX for PIC + let Defs = [O7] in { +@@ -503,7 +518,7 @@ defm SRA : F3_12<"sra", 0b100111, sra, IntRegs, i3 + defm ADD : F3_12<"add", 0b000000, add, IntRegs, i32, i32imm>; + + // "LEA" forms of add (patterns to make tblgen happy) +-let Predicates = [Is32Bit] in ++let Predicates = [Is32Bit], isCodeGenOnly = 1 in + def LEA_ADDri : F3_2<2, 0b000000, + (outs IntRegs:$dst), (ins MEMri:$addr), + "add ${addr:arith}, $dst", +Index: lib/Target/Sparc/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/CMakeLists.txt ++++ lib/Target/Sparc/CMakeLists.txt +@@ -4,6 +4,7 @@ tablegen(LLVM SparcGenRegisterInfo.inc -gen-regist + tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info) + tablegen(LLVM SparcGenCodeEmitter.inc -gen-emitter) + tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer) ++tablegen(LLVM SparcGenAsmMatcher.inc -gen-asm-matcher) + tablegen(LLVM SparcGenDAGISel.inc -gen-dag-isel) + tablegen(LLVM SparcGenSubtargetInfo.inc -gen-subtarget) + tablegen(LLVM SparcGenCallingConv.inc -gen-callingconv) +@@ -31,3 +32,4 @@ add_dependencies(LLVMSparcCodeGen SparcCommonTable + add_subdirectory(TargetInfo) + add_subdirectory(MCTargetDesc) + add_subdirectory(InstPrinter) ++add_subdirectory(AsmParser) +Index: lib/Target/Sparc/Makefile +=================================================================== +--- lib/Target/Sparc/Makefile ++++ lib/Target/Sparc/Makefile +@@ -13,11 +13,12 @@ TARGET = Sparc + + # Make sure that tblgen is run, first thing. + BUILT_SOURCES = SparcGenRegisterInfo.inc SparcGenInstrInfo.inc \ +- SparcGenAsmWriter.inc SparcGenDAGISel.inc \ ++ SparcGenAsmWriter.inc SparcGenAsmMatcher.inc \ ++ SparcGenDAGISel.inc \ + SparcGenSubtargetInfo.inc SparcGenCallingConv.inc \ + SparcGenCodeEmitter.inc + +-DIRS = InstPrinter TargetInfo MCTargetDesc ++DIRS = InstPrinter AsmParser TargetInfo MCTargetDesc + + include $(LEVEL)/Makefile.common + +Index: lib/Target/Sparc/Sparc.td +=================================================================== +--- lib/Target/Sparc/Sparc.td ++++ lib/Target/Sparc/Sparc.td +@@ -44,6 +44,10 @@ include "SparcInstrInfo.td" + + def SparcInstrInfo : InstrInfo; + ++def SparcAsmParser : AsmParser { ++ bit ShouldEmitMatchRegisterName = 0; ++} ++ + //===----------------------------------------------------------------------===// + // SPARC processors supported. + //===----------------------------------------------------------------------===// +@@ -77,6 +81,7 @@ def SparcAsmWriter : AsmWriter { + def Sparc : Target { + // Pull in Instruction Info: + let InstructionSet = SparcInstrInfo; ++ let AssemblyParsers = [SparcAsmParser]; + + let AssemblyWriters = [SparcAsmWriter]; + } +Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +=================================================================== +--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp ++++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +@@ -0,0 +1,614 @@ ++//===-- SparcAsmParser.cpp - Parse Sparc assembly to MCInst instructions --===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#include "MCTargetDesc/SparcMCTargetDesc.h" ++#include "llvm/ADT/STLExtras.h" ++#include "llvm/MC/MCContext.h" ++#include "llvm/MC/MCInst.h" ++#include "llvm/MC/MCParser/MCParsedAsmOperand.h" ++#include "llvm/MC/MCStreamer.h" ++#include "llvm/MC/MCSubtargetInfo.h" ++#include "llvm/MC/MCTargetAsmParser.h" ++#include "llvm/Support/TargetRegistry.h" ++ ++using namespace llvm; ++ ++// The generated AsmMatcher SparcGenAsmMatcher uses "Sparc" as the target ++// namespace. But SPARC backend uses "SP" as its namespace. ++namespace llvm { ++ namespace Sparc { ++ using namespace SP; ++ } ++} ++ ++namespace { ++class SparcAsmParser : public MCTargetAsmParser { ++ ++ MCSubtargetInfo &STI; ++ MCAsmParser &Parser; ++ ++ /// @name Auto-generated Match Functions ++ /// { ++ ++#define GET_ASSEMBLER_HEADER ++#include "SparcGenAsmMatcher.inc" ++ ++ /// } ++ ++ // public interface of the MCTargetAsmParser. ++ bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, ++ SmallVectorImpl<MCParsedAsmOperand*> &Operands, ++ MCStreamer &Out, unsigned &ErrorInfo, ++ bool MatchingInlineAsm); ++ bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc); ++ bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name, ++ SMLoc NameLoc, ++ SmallVectorImpl<MCParsedAsmOperand*> &Operands); ++ bool ParseDirective(AsmToken DirectiveID); ++ ++ ++ // Custom parse functions for Sparc specific operands. ++ OperandMatchResultTy ++ parseMEMrrOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands); ++ OperandMatchResultTy ++ parseMEMriOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands); ++ ++ OperandMatchResultTy ++ parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, ++ int ImmOffsetOrReg); ++ ++ OperandMatchResultTy ++ parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, ++ StringRef Name); ++ ++ // returns true if Tok is matched to a register and returns register in RegNo. ++ bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo, bool isDFP, ++ bool isQFP); ++ ++public: ++ SparcAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser, ++ const MCInstrInfo &MII) ++ : MCTargetAsmParser(), STI(sti), Parser(parser) { ++ // Initialize the set of available features. ++ setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); ++ } ++ ++}; ++ ++ static unsigned IntRegs[32] = { ++ Sparc::G0, Sparc::G1, Sparc::G2, Sparc::G3, ++ Sparc::G4, Sparc::G5, Sparc::G6, Sparc::G7, ++ Sparc::O0, Sparc::O1, Sparc::O2, Sparc::O3, ++ Sparc::O4, Sparc::O5, Sparc::O6, Sparc::O7, ++ Sparc::L0, Sparc::L1, Sparc::L2, Sparc::L3, ++ Sparc::L4, Sparc::L5, Sparc::L6, Sparc::L7, ++ Sparc::I0, Sparc::I1, Sparc::I2, Sparc::I3, ++ Sparc::I4, Sparc::I5, Sparc::I6, Sparc::I7 }; ++ ++ static unsigned FloatRegs[32] = { ++ Sparc::F0, Sparc::F1, Sparc::F2, Sparc::F3, ++ Sparc::F4, Sparc::F5, Sparc::F6, Sparc::F7, ++ Sparc::F8, Sparc::F9, Sparc::F10, Sparc::F11, ++ Sparc::F12, Sparc::F13, Sparc::F14, Sparc::F15, ++ Sparc::F16, Sparc::F17, Sparc::F18, Sparc::F19, ++ Sparc::F20, Sparc::F21, Sparc::F22, Sparc::F23, ++ Sparc::F24, Sparc::F25, Sparc::F26, Sparc::F27, ++ Sparc::F28, Sparc::F29, Sparc::F30, Sparc::F31 }; ++ ++ static unsigned DoubleRegs[32] = { ++ Sparc::D0, Sparc::D1, Sparc::D2, Sparc::D3, ++ Sparc::D4, Sparc::D5, Sparc::D6, Sparc::D7, ++ Sparc::D8, Sparc::D7, Sparc::D8, Sparc::D9, ++ Sparc::D12, Sparc::D13, Sparc::D14, Sparc::D15, ++ Sparc::D16, Sparc::D17, Sparc::D18, Sparc::D19, ++ Sparc::D20, Sparc::D21, Sparc::D22, Sparc::D23, ++ Sparc::D24, Sparc::D25, Sparc::D26, Sparc::D27, ++ Sparc::D28, Sparc::D29, Sparc::D30, Sparc::D31 }; ++ ++ static unsigned QuadFPRegs[32] = { ++ Sparc::Q0, Sparc::Q1, Sparc::Q2, Sparc::Q3, ++ Sparc::Q4, Sparc::Q5, Sparc::Q6, Sparc::Q7, ++ Sparc::Q8, Sparc::Q7, Sparc::Q8, Sparc::Q9, ++ Sparc::Q12, Sparc::Q13, Sparc::Q14, Sparc::Q15 }; ++ ++ ++/// SparcOperand - Instances of this class represent a parsed Sparc machine ++/// instruction. ++class SparcOperand : public MCParsedAsmOperand { ++public: ++ enum RegisterKind { ++ rk_None, ++ rk_IntReg, ++ rk_FloatReg, ++ rk_DoubleReg, ++ rk_QuadReg, ++ rk_CCReg, ++ rk_Y ++ }; ++private: ++ enum KindTy { ++ k_Token, ++ k_Register, ++ k_Immediate, ++ k_MemoryReg, ++ k_MemoryImm ++ } Kind; ++ ++ SMLoc StartLoc, EndLoc; ++ ++ SparcOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} ++ ++ struct Token { ++ const char *Data; ++ unsigned Length; ++ }; ++ ++ struct RegOp { ++ unsigned RegNum; ++ RegisterKind Kind; ++ }; ++ ++ struct ImmOp { ++ const MCExpr *Val; ++ }; ++ ++ struct MemOp { ++ unsigned Base; ++ unsigned OffsetReg; ++ const MCExpr *Off; ++ }; ++ ++ union { ++ struct Token Tok; ++ struct RegOp Reg; ++ struct ImmOp Imm; ++ struct MemOp Mem; ++ }; ++public: ++ bool isToken() const { return Kind == k_Token; } ++ bool isReg() const { return Kind == k_Register; } ++ bool isImm() const { return Kind == k_Immediate; } ++ bool isMem() const { return isMEMrr() || isMEMri(); } ++ bool isMEMrr() const { return Kind == k_MemoryReg; } ++ bool isMEMri() const { return Kind == k_MemoryImm; } ++ ++ StringRef getToken() const { ++ assert(Kind == k_Token && "Invalid access!"); ++ return StringRef(Tok.Data, Tok.Length); ++ } ++ ++ unsigned getReg() const { ++ assert((Kind == k_Register) && "Invalid access!"); ++ return Reg.RegNum; ++ } ++ ++ const MCExpr *getImm() const { ++ assert((Kind == k_Immediate) && "Invalid access!"); ++ return Imm.Val; ++ } ++ ++ unsigned getMemBase() const { ++ assert((Kind == k_MemoryReg || Kind == k_MemoryImm) && "Invalid access!"); ++ return Mem.Base; ++ } ++ ++ unsigned getMemOffsetReg() const { ++ assert((Kind == k_MemoryReg) && "Invalid access!"); ++ return Mem.OffsetReg; ++ } ++ ++ const MCExpr *getMemOff() const { ++ assert((Kind == k_MemoryImm) && "Invalid access!"); ++ return Mem.Off; ++ } ++ ++ /// getStartLoc - Get the location of the first token of this operand. ++ SMLoc getStartLoc() const { ++ return StartLoc; ++ } ++ /// getEndLoc - Get the location of the last token of this operand. ++ SMLoc getEndLoc() const { ++ return EndLoc; ++ } ++ ++ virtual void print(raw_ostream &OS) const { ++ switch (Kind) { ++ case k_Token: OS << "Token: " << getToken() << "\n"; break; ++ case k_Register: OS << "Reg: #" << getReg() << "\n"; break; ++ case k_Immediate: OS << "Imm: " << getImm() << "\n"; break; ++ case k_MemoryReg: OS << "Mem: " << getMemBase() << "+" ++ << getMemOffsetReg() << "\n"; break; ++ case k_MemoryImm: assert(getMemOff() != 0); ++ OS << "Mem: " << getMemBase() ++ << "+" << *getMemOff() ++ << "\n"; break; ++ } ++ } ++ ++ void addRegOperands(MCInst &Inst, unsigned N) const { ++ assert(N == 1 && "Invalid number of operands!"); ++ Inst.addOperand(MCOperand::CreateReg(getReg())); ++ } ++ ++ void addImmOperands(MCInst &Inst, unsigned N) const { ++ assert(N == 1 && "Invalid number of operands!"); ++ const MCExpr *Expr = getImm(); ++ addExpr(Inst, Expr); ++ } ++ ++ void addExpr(MCInst &Inst, const MCExpr *Expr) const{ ++ // Add as immediate when possible. Null MCExpr = 0. ++ if (Expr == 0) ++ Inst.addOperand(MCOperand::CreateImm(0)); ++ else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr)) ++ Inst.addOperand(MCOperand::CreateImm(CE->getValue())); ++ else ++ Inst.addOperand(MCOperand::CreateExpr(Expr)); ++ } ++ ++ void addMEMrrOperands(MCInst &Inst, unsigned N) const { ++ assert(N == 2 && "Invalid number of operands!"); ++ ++ Inst.addOperand(MCOperand::CreateReg(getMemBase())); ++ ++ assert(getMemOffsetReg() != 0 && "Invalid offset"); ++ Inst.addOperand(MCOperand::CreateReg(getMemOffsetReg())); ++ } ++ ++ void addMEMriOperands(MCInst &Inst, unsigned N) const { ++ assert(N == 2 && "Invalid number of operands!"); ++ ++ Inst.addOperand(MCOperand::CreateReg(getMemBase())); ++ ++ const MCExpr *Expr = getMemOff(); ++ addExpr(Inst, Expr); ++ } ++ ++ static SparcOperand *CreateToken(StringRef Str, SMLoc S) { ++ SparcOperand *Op = new SparcOperand(k_Token); ++ Op->Tok.Data = Str.data(); ++ Op->Tok.Length = Str.size(); ++ Op->StartLoc = S; ++ Op->EndLoc = S; ++ return Op; ++ } ++ ++ static SparcOperand *CreateReg(unsigned RegNum, ++ SparcOperand::RegisterKind Kind, ++ SMLoc S, SMLoc E) { ++ SparcOperand *Op = new SparcOperand(k_Register); ++ Op->Reg.RegNum = RegNum; ++ Op->Reg.Kind = Kind; ++ Op->StartLoc = S; ++ Op->EndLoc = E; ++ return Op; ++ } ++ ++ static SparcOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) { ++ SparcOperand *Op = new SparcOperand(k_Immediate); ++ Op->Imm.Val = Val; ++ Op->StartLoc = S; ++ Op->EndLoc = E; ++ return Op; ++ } ++ ++ ++}; ++ ++} // end namespace ++ ++bool SparcAsmParser:: ++MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, ++ SmallVectorImpl<MCParsedAsmOperand*> &Operands, ++ MCStreamer &Out, unsigned &ErrorInfo, ++ bool MatchingInlineAsm) { ++ MCInst Inst; ++ SmallVector<MCInst, 8> Instructions; ++ unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo, ++ MatchingInlineAsm); ++ switch (MatchResult) { ++ default: ++ break; ++ ++ case Match_Success: { ++ Inst.setLoc(IDLoc); ++ Out.EmitInstruction(Inst); ++ return false; ++ } ++ ++ case Match_MissingFeature: ++ return Error(IDLoc, ++ "instruction requires a CPU feature not currently enabled"); ++ ++ case Match_InvalidOperand: { ++ SMLoc ErrorLoc = IDLoc; ++ if (ErrorInfo != ~0U) { ++ if (ErrorInfo >= Operands.size()) ++ return Error(IDLoc, "too few operands for instruction"); ++ ++ ErrorLoc = ((SparcOperand*) Operands[ErrorInfo])->getStartLoc(); ++ if (ErrorLoc == SMLoc()) ++ ErrorLoc = IDLoc; ++ } ++ ++ return Error(ErrorLoc, "invalid operand for instruction"); ++ } ++ case Match_MnemonicFail: ++ return Error(IDLoc, "invalid instruction"); ++ } ++ return true; ++} ++ ++bool SparcAsmParser:: ++ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) ++{ ++ const AsmToken &Tok = Parser.getTok(); ++ StartLoc = Tok.getLoc(); ++ EndLoc = Tok.getEndLoc(); ++ RegNo = 0; ++ if (getLexer().getKind() != AsmToken::Percent) ++ return false; ++ Parser.Lex(); ++ if (matchRegisterName(Tok, RegNo, false, false)) { ++ Parser.Lex(); ++ return false; ++ } ++ ++ return Error(StartLoc, "invalid register name"); ++} ++ ++bool SparcAsmParser:: ++ParseInstruction(ParseInstructionInfo &Info, StringRef Name, ++ SMLoc NameLoc, ++ SmallVectorImpl<MCParsedAsmOperand*> &Operands) ++{ ++ // Check if we have valid mnemonic. ++ if (!mnemonicIsValid(Name, 0)) { ++ Parser.eatToEndOfStatement(); ++ return Error(NameLoc, "Unknown instruction"); ++ } ++ // First operand in MCInst is instruction mnemonic. ++ Operands.push_back(SparcOperand::CreateToken(Name, NameLoc)); ++ ++ if (getLexer().isNot(AsmToken::EndOfStatement)) { ++ // Read the first operand. ++ if (parseOperand(Operands, Name) != MatchOperand_Success) { ++ SMLoc Loc = getLexer().getLoc(); ++ Parser.eatToEndOfStatement(); ++ return Error(Loc, "unexpected token"); ++ } ++ ++ while (getLexer().is(AsmToken::Comma)) { ++ Parser.Lex(); // Eat the comma. ++ // Parse and remember the operand. ++ if (parseOperand(Operands, Name) != MatchOperand_Success) { ++ SMLoc Loc = getLexer().getLoc(); ++ Parser.eatToEndOfStatement(); ++ return Error(Loc, "unexpected token"); ++ } ++ } ++ } ++ if (getLexer().isNot(AsmToken::EndOfStatement)) { ++ SMLoc Loc = getLexer().getLoc(); ++ Parser.eatToEndOfStatement(); ++ return Error(Loc, "unexpected token"); ++ } ++ Parser.Lex(); // Consume the EndOfStatement. ++ return false; ++} ++ ++bool SparcAsmParser:: ++ParseDirective(AsmToken DirectiveID) ++{ ++ // Ignore all directives for now. ++ Parser.eatToEndOfStatement(); ++ return false; ++} ++ ++SparcAsmParser::OperandMatchResultTy SparcAsmParser:: ++parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, ++ int ImmOffsetOrReg) ++{ ++ // FIXME: Implement memory operand parsing here. ++ return MatchOperand_NoMatch; ++} ++ ++SparcAsmParser::OperandMatchResultTy SparcAsmParser:: ++parseMEMrrOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) ++{ ++ return parseMEMOperand(Operands, 2); ++} ++ ++SparcAsmParser::OperandMatchResultTy SparcAsmParser:: ++parseMEMriOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) ++{ ++ return parseMEMOperand(Operands, 1); ++} ++ ++SparcAsmParser::OperandMatchResultTy SparcAsmParser:: ++parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, ++ StringRef Mnemonic) ++{ ++ OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic); ++ if (ResTy == MatchOperand_Success) ++ return ResTy; ++ // If there wasn't a custom match, try the generic matcher below. Otherwise, ++ // there was a match, but an error occurred, in which case, just return that ++ // the operand parsing failed. ++ if (ResTy == MatchOperand_ParseFail) ++ return ResTy; ++ ++ SMLoc S = Parser.getTok().getLoc(); ++ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); ++ const MCExpr *EVal; ++ SparcOperand *Op; ++ switch (getLexer().getKind()) { ++ case AsmToken::Percent: ++ Parser.Lex(); // Eat the '%'. ++ unsigned RegNo; ++ if (matchRegisterName(Parser.getTok(), RegNo, false, false)) { ++ Parser.Lex(); // Eat the identifier token. ++ Op = SparcOperand::CreateReg(RegNo, SparcOperand::rk_None, S, E); ++ break; ++ } ++ // FIXME: Handle modifiers like %hi, %lo etc., ++ return MatchOperand_ParseFail; ++ ++ case AsmToken::Minus: ++ case AsmToken::Integer: ++ if (getParser().parseExpression(EVal)) ++ return MatchOperand_ParseFail; ++ ++ Op = SparcOperand::CreateImm(EVal, S, E); ++ break; ++ ++ case AsmToken::Identifier: { ++ StringRef Identifier; ++ if (getParser().parseIdentifier(Identifier)) ++ return MatchOperand_ParseFail; ++ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); ++ MCSymbol *Sym = getContext().GetOrCreateSymbol(Identifier); ++ ++ // Otherwise create a symbol reference. ++ const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, ++ getContext()); ++ ++ Op = SparcOperand::CreateImm(Res, S, E); ++ break; ++ } ++ ++ case AsmToken::LBrac: // handle [ ++ return parseMEMOperand(Operands, 0); ++ ++ default: ++ return MatchOperand_ParseFail; ++ } ++ // Push the parsed operand into the list of operands ++ Operands.push_back(Op); ++ return MatchOperand_Success; ++} ++ ++bool SparcAsmParser::matchRegisterName(const AsmToken &Tok, ++ unsigned &RegNo, ++ bool isDFP, ++ bool isQFP) ++{ ++ int64_t intVal = 0; ++ RegNo = 0; ++ if (Tok.is(AsmToken::Identifier)) { ++ StringRef name = Tok.getString(); ++ ++ // %fp ++ if (name.equals("fp")) { ++ RegNo = Sparc::I6; ++ return true; ++ } ++ // %sp ++ if (name.equals("sp")) { ++ RegNo = Sparc::O6; ++ return true; ++ } ++ ++ if (name.equals("y")) { ++ RegNo = Sparc::Y; ++ return true; ++ } ++ ++ if (name.equals("icc")) { ++ RegNo = Sparc::ICC; ++ return true; ++ } ++ ++ if (name.equals("xcc")) { ++ // FIXME:: check 64bit. ++ RegNo = Sparc::ICC; ++ return true; ++ } ++ ++ // %fcc0 - %fcc3 ++ if (name.substr(0, 3).equals_lower("fcc") ++ && !name.substr(3).getAsInteger(10, intVal) ++ && intVal < 4) { ++ // FIXME: check 64bit and handle %fcc1 - %fcc3 ++ RegNo = Sparc::FCC; ++ return true; ++ } ++ ++ // %g0 - %g7 ++ if (name.substr(0, 1).equals_lower("g") ++ && !name.substr(1).getAsInteger(10, intVal) ++ && intVal < 8) { ++ RegNo = IntRegs[intVal]; ++ return true; ++ } ++ // %o0 - %o7 ++ if (name.substr(0, 1).equals_lower("o") ++ && !name.substr(1).getAsInteger(10, intVal) ++ && intVal < 8) { ++ RegNo = IntRegs[8 + intVal]; ++ return true; ++ } ++ if (name.substr(0, 1).equals_lower("l") ++ && !name.substr(1).getAsInteger(10, intVal) ++ && intVal < 8) { ++ RegNo = IntRegs[16 + intVal]; ++ return true; ++ } ++ if (name.substr(0, 1).equals_lower("i") ++ && !name.substr(1).getAsInteger(10, intVal) ++ && intVal < 8) { ++ RegNo = IntRegs[24 + intVal]; ++ return true; ++ } ++ // %f0 - %f31 ++ if (name.substr(0, 1).equals_lower("f") ++ && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 32) { ++ if (isDFP && (intVal%2 == 0)) { ++ RegNo = DoubleRegs[intVal/2]; ++ } else if (isQFP && (intVal%4 == 0)) { ++ RegNo = QuadFPRegs[intVal/4]; ++ } else { ++ RegNo = FloatRegs[intVal]; ++ } ++ return true; ++ } ++ // %f32 - %f62 ++ if (name.substr(0, 1).equals_lower("f") ++ && !name.substr(1, 2).getAsInteger(10, intVal) ++ && intVal >= 32 && intVal <= 62 && (intVal % 2 == 0)) { ++ if (isDFP) { ++ RegNo = DoubleRegs[16 + intVal/2]; ++ } else if (isQFP && (intVal % 4 == 0)) { ++ RegNo = QuadFPRegs[8 + intVal/4]; ++ } else { ++ return false; ++ } ++ return true; ++ } ++ ++ // %r0 - %r31 ++ if (name.substr(0, 1).equals_lower("r") ++ && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 31) { ++ RegNo = IntRegs[intVal]; ++ return true; ++ } ++ } ++ return false; ++} ++ ++ ++ ++extern "C" void LLVMInitializeSparcAsmParser() { ++ RegisterMCAsmParser<SparcAsmParser> A(TheSparcTarget); ++ RegisterMCAsmParser<SparcAsmParser> B(TheSparcV9Target); ++} ++ ++#define GET_REGISTER_MATCHER ++#define GET_MATCHER_IMPLEMENTATION ++#include "SparcGenAsmMatcher.inc" +Index: lib/Target/Sparc/AsmParser/LLVMBuild.txt +=================================================================== +--- lib/Target/Sparc/AsmParser/LLVMBuild.txt ++++ lib/Target/Sparc/AsmParser/LLVMBuild.txt +@@ -0,0 +1,23 @@ ++;===- ./lib/Target/Sparc/AsmParser/LLVMBuild.txt ---------------*- Conf -*--===; ++; ++; The LLVM Compiler Infrastructure ++; ++; This file is distributed under the University of Illinois Open Source ++; License. See LICENSE.TXT for details. ++; ++;===------------------------------------------------------------------------===; ++; ++; This is an LLVMBuild description file for the components in this subdirectory. ++; ++; For more information on the LLVMBuild system, please see: ++; ++; http://llvm.org/docs/LLVMBuild.html ++; ++;===------------------------------------------------------------------------===; ++ ++[component_0] ++type = Library ++name = SparcAsmParser ++parent = Sparc ++required_libraries = MC MCParser Support SparcDesc SparcInfo ++add_to_library_groups = Sparc +Index: lib/Target/Sparc/AsmParser/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/AsmParser/CMakeLists.txt ++++ lib/Target/Sparc/AsmParser/CMakeLists.txt +@@ -0,0 +1,3 @@ ++add_llvm_library(LLVMSparcAsmParser ++ SparcAsmParser.cpp ++ ) +Index: lib/Target/Sparc/AsmParser/Makefile +=================================================================== +--- lib/Target/Sparc/AsmParser/Makefile ++++ lib/Target/Sparc/AsmParser/Makefile +@@ -0,0 +1,15 @@ ++##===- lib/Target/Sparc/AsmParser/Makefile ------------------*- Makefile-*-===## ++# ++# The LLVM Compiler Infrastructure ++# ++# This file is distributed under the University of Illinois Open Source ++# License. See LICENSE.TXT for details. ++# ++##===----------------------------------------------------------------------===## ++LEVEL = ../../../.. ++LIBRARYNAME = LLVMSparcAsmParser ++ ++# Hack: we need to include 'main' Sparc target directory to grab private headers ++CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. ++ ++include $(LEVEL)/Makefile.common +Index: lib/Target/Sparc/SparcInstr64Bit.td +=================================================================== +--- lib/Target/Sparc/SparcInstr64Bit.td ++++ lib/Target/Sparc/SparcInstr64Bit.td +@@ -176,11 +176,11 @@ def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMP + def : Pat<(ctpop i64:$src), (POPCrr $src)>; + + // "LEA" form of add ++let isCodeGenOnly = 1 in + def LEAX_ADDri : F3_2<2, 0b000000, + (outs I64Regs:$dst), (ins MEMri:$addr), + "add ${addr:arith}, $dst", + [(set iPTR:$dst, ADDRri:$addr)]>; +- + } // Predicates = [Is64Bit] + + diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198533-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198533-sparc.diff new file mode 100644 index 0000000..d6e65da --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198533-sparc.diff @@ -0,0 +1,516 @@ +Pull in r198533 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add initial implementation of MC Code emitter for sparc. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -100,9 +100,14 @@ def MEMri : Operand<iPTR> { + def TLSSym : Operand<iPTR>; + + // Branch targets have OtherVT type. +-def brtarget : Operand<OtherVT>; +-def calltarget : Operand<i32>; ++def brtarget : Operand<OtherVT> { ++ let EncoderMethod = "getBranchTargetOpValue"; ++} + ++def calltarget : Operand<i32> { ++ let EncoderMethod = "getCallTargetOpValue"; ++} ++ + // Operand for printing out a condition code. + let PrintMethod = "printCCOperand" in + def CCOp : Operand<i32>; +Index: lib/Target/Sparc/MCTargetDesc/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/CMakeLists.txt ++++ lib/Target/Sparc/MCTargetDesc/CMakeLists.txt +@@ -1,6 +1,8 @@ + add_llvm_library(LLVMSparcDesc ++ SparcAsmBackend.cpp ++ SparcMCAsmInfo.cpp ++ SparcMCCodeEmitter.cpp + SparcMCTargetDesc.cpp +- SparcMCAsmInfo.cpp + SparcMCExpr.cpp + SparcTargetStreamer.cpp + ) +Index: lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp +@@ -0,0 +1,131 @@ ++//===-- SparcMCCodeEmitter.cpp - Convert Sparc code to machine code -------===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++// ++// This file implements the SparcMCCodeEmitter class. ++// ++//===----------------------------------------------------------------------===// ++ ++#define DEBUG_TYPE "mccodeemitter" ++#include "SparcMCTargetDesc.h" ++#include "MCTargetDesc/SparcFixupKinds.h" ++#include "llvm/MC/MCCodeEmitter.h" ++#include "llvm/MC/MCContext.h" ++#include "llvm/MC/MCExpr.h" ++#include "llvm/MC/MCInst.h" ++#include "llvm/MC/MCRegisterInfo.h" ++#include "llvm/ADT/Statistic.h" ++#include "llvm/Support/raw_ostream.h" ++ ++using namespace llvm; ++ ++STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); ++ ++namespace { ++class SparcMCCodeEmitter : public MCCodeEmitter { ++ SparcMCCodeEmitter(const SparcMCCodeEmitter &) LLVM_DELETED_FUNCTION; ++ void operator=(const SparcMCCodeEmitter &) LLVM_DELETED_FUNCTION; ++ MCContext &Ctx; ++ ++public: ++ SparcMCCodeEmitter(MCContext &ctx): Ctx(ctx) {} ++ ++ ~SparcMCCodeEmitter() {} ++ ++ void EncodeInstruction(const MCInst &MI, raw_ostream &OS, ++ SmallVectorImpl<MCFixup> &Fixups) const; ++ ++ // getBinaryCodeForInstr - TableGen'erated function for getting the ++ // binary encoding for an instruction. ++ uint64_t getBinaryCodeForInstr(const MCInst &MI, ++ SmallVectorImpl<MCFixup> &Fixups) const; ++ ++ /// getMachineOpValue - Return binary encoding of operand. If the machine ++ /// operand requires relocation, record the relocation and return zero. ++ unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, ++ SmallVectorImpl<MCFixup> &Fixups) const; ++ ++ unsigned getCallTargetOpValue(const MCInst &MI, unsigned OpNo, ++ SmallVectorImpl<MCFixup> &Fixups) const; ++ unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, ++ SmallVectorImpl<MCFixup> &Fixups) const; ++ ++}; ++} // end anonymous namespace ++ ++MCCodeEmitter *llvm::createSparcMCCodeEmitter(const MCInstrInfo &MCII, ++ const MCRegisterInfo &MRI, ++ const MCSubtargetInfo &STI, ++ MCContext &Ctx) { ++ return new SparcMCCodeEmitter(Ctx); ++} ++ ++void SparcMCCodeEmitter:: ++EncodeInstruction(const MCInst &MI, raw_ostream &OS, ++ SmallVectorImpl<MCFixup> &Fixups) const { ++ unsigned Bits = getBinaryCodeForInstr(MI, Fixups); ++ ++ // Output the constant in big endian byte order. ++ for (unsigned i = 0; i != 4; ++i) { ++ OS << (char)(Bits >> 24); ++ Bits <<= 8; ++ } ++ ++ ++MCNumEmitted; // Keep track of the # of mi's emitted. ++} ++ ++ ++unsigned SparcMCCodeEmitter:: ++getMachineOpValue(const MCInst &MI, const MCOperand &MO, ++ SmallVectorImpl<MCFixup> &Fixups) const { ++ ++ if (MO.isReg()) ++ return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); ++ ++ if (MO.isImm()) ++ return MO.getImm(); ++ ++ assert(MO.isExpr()); ++ const MCExpr *Expr = MO.getExpr(); ++ int64_t Res; ++ if (Expr->EvaluateAsAbsolute(Res)) ++ return Res; ++ ++ assert(0 && "Unhandled expression!"); ++ return 0; ++} ++ ++unsigned SparcMCCodeEmitter:: ++getCallTargetOpValue(const MCInst &MI, unsigned OpNo, ++ SmallVectorImpl<MCFixup> &Fixups) const { ++ const MCOperand &MO = MI.getOperand(OpNo); ++ if (MO.isReg() || MO.isImm()) ++ return getMachineOpValue(MI, MO, Fixups); ++ ++ Fixups.push_back(MCFixup::Create(0, MO.getExpr(), ++ (MCFixupKind)Sparc::fixup_sparc_call30)); ++ return 0; ++} ++ ++unsigned SparcMCCodeEmitter:: ++getBranchTargetOpValue(const MCInst &MI, unsigned OpNo, ++ SmallVectorImpl<MCFixup> &Fixups) const { ++ const MCOperand &MO = MI.getOperand(OpNo); ++ if (MO.isReg() || MO.isImm()) ++ return getMachineOpValue(MI, MO, Fixups); ++ ++ Sparc::Fixups fixup = Sparc::fixup_sparc_br22; ++ if (MI.getOpcode() == SP::BPXCC) ++ fixup = Sparc::fixup_sparc_br19; ++ ++ Fixups.push_back(MCFixup::Create(0, MO.getExpr(), ++ (MCFixupKind)fixup)); ++ return 0; ++} ++ ++#include "SparcGenMCCodeEmitter.inc" +Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +@@ -136,6 +136,18 @@ extern "C" void LLVMInitializeSparcTargetMC() { + TargetRegistry::RegisterMCSubtargetInfo(TheSparcV9Target, + createSparcMCSubtargetInfo); + ++ // Register the MC Code Emitter. ++ TargetRegistry::RegisterMCCodeEmitter(TheSparcTarget, ++ createSparcMCCodeEmitter); ++ TargetRegistry::RegisterMCCodeEmitter(TheSparcV9Target, ++ createSparcMCCodeEmitter); ++ ++ //Register the asm backend. ++ TargetRegistry::RegisterMCAsmBackend(TheSparcTarget, ++ createSparcAsmBackend); ++ TargetRegistry::RegisterMCAsmBackend(TheSparcV9Target, ++ createSparcAsmBackend); ++ + TargetRegistry::RegisterAsmStreamer(TheSparcTarget, + createMCAsmStreamer); + TargetRegistry::RegisterAsmStreamer(TheSparcV9Target, +Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +@@ -0,0 +1,101 @@ ++//===-- SparcAsmBackend.cpp - Sparc Assembler Backend ---------------------===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#include "llvm/MC/MCAsmBackend.h" ++#include "MCTargetDesc/SparcMCTargetDesc.h" ++#include "MCTargetDesc/SparcFixupKinds.h" ++#include "llvm/MC/MCFixupKindInfo.h" ++#include "llvm/MC/MCObjectWriter.h" ++#include "llvm/Support/TargetRegistry.h" ++ ++using namespace llvm; ++ ++namespace { ++ class SparcAsmBackend : public MCAsmBackend { ++ ++ public: ++ SparcAsmBackend(const Target &T) : MCAsmBackend() {} ++ ++ unsigned getNumFixupKinds() const { ++ return Sparc::NumTargetFixupKinds; ++ } ++ ++ const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const { ++ const static MCFixupKindInfo Infos[Sparc::NumTargetFixupKinds] = { ++ // name offset bits flags ++ { "fixup_sparc_call30", 0, 30, MCFixupKindInfo::FKF_IsPCRel }, ++ { "fixup_sparc_br22", 0, 22, MCFixupKindInfo::FKF_IsPCRel }, ++ { "fixup_sparc_br19", 0, 19, MCFixupKindInfo::FKF_IsPCRel } ++ }; ++ ++ if (Kind < FirstTargetFixupKind) ++ return MCAsmBackend::getFixupKindInfo(Kind); ++ ++ assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && ++ "Invalid kind!"); ++ return Infos[Kind - FirstTargetFixupKind]; ++ } ++ ++ bool mayNeedRelaxation(const MCInst &Inst) const { ++ // FIXME. ++ return false; ++ } ++ ++ /// fixupNeedsRelaxation - Target specific predicate for whether a given ++ /// fixup requires the associated instruction to be relaxed. ++ bool fixupNeedsRelaxation(const MCFixup &Fixup, ++ uint64_t Value, ++ const MCRelaxableFragment *DF, ++ const MCAsmLayout &Layout) const { ++ // FIXME. ++ assert(0 && "fixupNeedsRelaxation() unimplemented"); ++ return false; ++ } ++ void relaxInstruction(const MCInst &Inst, MCInst &Res) const { ++ // FIXME. ++ assert(0 && "relaxInstruction() unimplemented"); ++ } ++ ++ bool writeNopData(uint64_t Count, MCObjectWriter *OW) const { ++ // FIXME: Zero fill for now. ++ for (uint64_t i = 0; i != Count; ++i) ++ OW->Write8(0); ++ return true; ++ } ++ }; ++ ++ class ELFSparcAsmBackend : public SparcAsmBackend { ++ public: ++ ELFSparcAsmBackend(const Target &T, Triple::OSType OSType) : ++ SparcAsmBackend(T) { } ++ ++ void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, ++ uint64_t Value) const { ++ assert(0 && "applyFixup not implemented yet"); ++ } ++ ++ MCObjectWriter *createObjectWriter(raw_ostream &OS) const { ++ assert(0 && "Object Writer not implemented yet"); ++ return 0; ++ } ++ ++ virtual bool doesSectionRequireSymbols(const MCSection &Section) const { ++ return false; ++ } ++ }; ++ ++} // end anonymous namespace ++ ++ ++MCAsmBackend *llvm::createSparcAsmBackend(const Target &T, ++ const MCRegisterInfo &MRI, ++ StringRef TT, ++ StringRef CPU) { ++ return new ELFSparcAsmBackend(T, Triple(TT).getOS()); ++} +Index: lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h ++++ lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h +@@ -0,0 +1,36 @@ ++//===-- SparcFixupKinds.h - Sparc Specific Fixup Entries --------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#ifndef LLVM_SPARC_FIXUPKINDS_H ++#define LLVM_SPARC_FIXUPKINDS_H ++ ++#include "llvm/MC/MCFixup.h" ++ ++namespace llvm { ++ namespace Sparc { ++ enum Fixups { ++ // fixup_sparc_call30 - 30-bit PC relative relocation for call ++ fixup_sparc_call30 = FirstTargetFixupKind, ++ ++ /// fixup_sparc_br22 - 22-bit PC relative relocation for ++ /// branches ++ fixup_sparc_br22, ++ ++ /// fixup_sparc_br22 - 22-bit PC relative relocation for ++ /// branches on icc/xcc ++ fixup_sparc_br19, ++ ++ // Marker ++ LastTargetFixupKind, ++ NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind ++ }; ++ } ++} ++ ++#endif +Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h ++++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h +@@ -15,11 +15,27 @@ + #define SPARCMCTARGETDESC_H + + namespace llvm { ++class MCAsmBackend; ++class MCCodeEmitter; ++class MCContext; ++class MCInstrInfo; ++class MCRegisterInfo; ++class MCSubtargetInfo; + class Target; ++class StringRef; + + extern Target TheSparcTarget; + extern Target TheSparcV9Target; + ++MCCodeEmitter *createSparcMCCodeEmitter(const MCInstrInfo &MCII, ++ const MCRegisterInfo &MRI, ++ const MCSubtargetInfo &STI, ++ MCContext &Ctx); ++MCAsmBackend *createSparcAsmBackend(const Target &T, ++ const MCRegisterInfo &MRI, ++ StringRef TT, ++ StringRef CPU); ++ + } // End llvm namespace + + // Defines symbolic names for Sparc registers. This defines a mapping from +Index: lib/Target/Sparc/Makefile +=================================================================== +--- lib/Target/Sparc/Makefile ++++ lib/Target/Sparc/Makefile +@@ -16,7 +16,7 @@ BUILT_SOURCES = SparcGenRegisterInfo.inc SparcGenI + SparcGenAsmWriter.inc SparcGenAsmMatcher.inc \ + SparcGenDAGISel.inc \ + SparcGenSubtargetInfo.inc SparcGenCallingConv.inc \ +- SparcGenCodeEmitter.inc ++ SparcGenCodeEmitter.inc SparcGenMCCodeEmitter.inc + + DIRS = InstPrinter AsmParser TargetInfo MCTargetDesc + +Index: lib/Target/Sparc/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/CMakeLists.txt ++++ lib/Target/Sparc/CMakeLists.txt +@@ -3,6 +3,7 @@ set(LLVM_TARGET_DEFINITIONS Sparc.td) + tablegen(LLVM SparcGenRegisterInfo.inc -gen-register-info) + tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info) + tablegen(LLVM SparcGenCodeEmitter.inc -gen-emitter) ++tablegen(LLVM SparcGenMCCodeEmitter.inc -gen-emitter -mc-emitter) + tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer) + tablegen(LLVM SparcGenAsmMatcher.inc -gen-asm-matcher) + tablegen(LLVM SparcGenDAGISel.inc -gen-dag-isel) +Index: lib/Target/Sparc/SparcCodeEmitter.cpp +=================================================================== +--- lib/Target/Sparc/SparcCodeEmitter.cpp ++++ lib/Target/Sparc/SparcCodeEmitter.cpp +@@ -72,6 +72,11 @@ class SparcCodeEmitter : public MachineFunctionPas + unsigned getMachineOpValue(const MachineInstr &MI, + const MachineOperand &MO) const; + ++ unsigned getCallTargetOpValue(const MachineInstr &MI, ++ unsigned) const; ++ unsigned getBranchTargetOpValue(const MachineInstr &MI, ++ unsigned) const; ++ + void emitWord(unsigned Word); + + unsigned getRelocation(const MachineInstr &MI, +@@ -181,6 +186,18 @@ unsigned SparcCodeEmitter::getMachineOpValue(const + llvm_unreachable("Unable to encode MachineOperand!"); + return 0; + } ++unsigned SparcCodeEmitter::getCallTargetOpValue(const MachineInstr &MI, ++ unsigned opIdx) const { ++ const MachineOperand MO = MI.getOperand(opIdx); ++ return getMachineOpValue(MI, MO); ++} ++ ++unsigned SparcCodeEmitter::getBranchTargetOpValue(const MachineInstr &MI, ++ unsigned opIdx) const { ++ const MachineOperand MO = MI.getOperand(opIdx); ++ return getMachineOpValue(MI, MO); ++} ++ + unsigned SparcCodeEmitter::getRelocation(const MachineInstr &MI, + const MachineOperand &MO) const { + +Index: test/MC/Sparc/sparc-alu-instructions.s +=================================================================== +--- test/MC/Sparc/sparc-alu-instructions.s ++++ test/MC/Sparc/sparc-alu-instructions.s +@@ -0,0 +1,72 @@ ++! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s ++! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s ++ ++ ! CHECK: add %g0, %g0, %g0 ! encoding: [0x80,0x00,0x00,0x00] ++ add %g0, %g0, %g0 ++ ! CHECK: add %g1, %g2, %g3 ! encoding: [0x86,0x00,0x40,0x02] ++ add %g1, %g2, %g3 ++ ! CHECK: add %o0, %o1, %l0 ! encoding: [0xa0,0x02,0x00,0x09] ++ add %r8, %r9, %l0 ++ ! CHECK: add %o0, 10, %l0 ! encoding: [0xa0,0x02,0x20,0x0a] ++ add %o0, 10, %l0 ++ ++ ! CHECK: addcc %g1, %g2, %g3 ! encoding: [0x86,0x80,0x40,0x02] ++ addcc %g1, %g2, %g3 ++ ++ ! CHECK: addxcc %g1, %g2, %g3 ! encoding: [0x86,0xc0,0x40,0x02] ++ addxcc %g1, %g2, %g3 ++ ++ ! CHECK: udiv %g1, %g2, %g3 ! encoding: [0x86,0x70,0x40,0x02] ++ udiv %g1, %g2, %g3 ++ ++ ! CHECK: sdiv %g1, %g2, %g3 ! encoding: [0x86,0x78,0x40,0x02] ++ sdiv %g1, %g2, %g3 ++ ++ ! CHECK: and %g1, %g2, %g3 ! encoding: [0x86,0x08,0x40,0x02] ++ and %g1, %g2, %g3 ++ ! CHECK: andn %g1, %g2, %g3 ! encoding: [0x86,0x28,0x40,0x02] ++ andn %g1, %g2, %g3 ++ ! CHECK: or %g1, %g2, %g3 ! encoding: [0x86,0x10,0x40,0x02] ++ or %g1, %g2, %g3 ++ ! CHECK: orn %g1, %g2, %g3 ! encoding: [0x86,0x30,0x40,0x02] ++ orn %g1, %g2, %g3 ++ ! CHECK: xor %g1, %g2, %g3 ! encoding: [0x86,0x18,0x40,0x02] ++ xor %g1, %g2, %g3 ++ ! CHECK: xnor %g1, %g2, %g3 ! encoding: [0x86,0x38,0x40,0x02] ++ xnor %g1, %g2, %g3 ++ ++ ! CHECK: umul %g1, %g2, %g3 ! encoding: [0x86,0x50,0x40,0x02] ++ umul %g1, %g2, %g3 ++ ++ ! CHECK: smul %g1, %g2, %g3 ! encoding: [0x86,0x58,0x40,0x02] ++ smul %g1, %g2, %g3 ++ ++ ! CHECK: nop ! encoding: [0x01,0x00,0x00,0x00] ++ nop ++ ++ ! CHECK: sethi 10, %l0 ! encoding: [0x21,0x00,0x00,0x0a] ++ sethi 10, %l0 ++ ++ ! CHECK: sll %g1, %g2, %g3 ! encoding: [0x87,0x28,0x40,0x02] ++ sll %g1, %g2, %g3 ++ ! CHECK: sll %g1, 31, %g3 ! encoding: [0x87,0x28,0x60,0x1f] ++ sll %g1, 31, %g3 ++ ++ ! CHECK: srl %g1, %g2, %g3 ! encoding: [0x87,0x30,0x40,0x02] ++ srl %g1, %g2, %g3 ++ ! CHECK: srl %g1, 31, %g3 ! encoding: [0x87,0x30,0x60,0x1f] ++ srl %g1, 31, %g3 ++ ++ ! CHECK: sra %g1, %g2, %g3 ! encoding: [0x87,0x38,0x40,0x02] ++ sra %g1, %g2, %g3 ++ ! CHECK: sra %g1, 31, %g3 ! encoding: [0x87,0x38,0x60,0x1f] ++ sra %g1, 31, %g3 ++ ++ ! CHECK: sub %g1, %g2, %g3 ! encoding: [0x86,0x20,0x40,0x02] ++ sub %g1, %g2, %g3 ++ ! CHECK: subcc %g1, %g2, %g3 ! encoding: [0x86,0xa0,0x40,0x02] ++ subcc %g1, %g2, %g3 ++ ++ ! CHECK: subxcc %g1, %g2, %g3 ! encoding: [0x86,0xe0,0x40,0x02] ++ subxcc %g1, %g2, %g3 ++ diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198565-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198565-sparc.diff new file mode 100644 index 0000000..cf32440 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198565-sparc.diff @@ -0,0 +1,76 @@ +Pull in r198565 from upstream llvm trunk (by Venkatraman Govindaraju): + + ELF relocation types for sparc. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: include/llvm/Support/ELF.h +=================================================================== +--- include/llvm/Support/ELF.h ++++ include/llvm/Support/ELF.h +@@ -1087,6 +1087,65 @@ enum { + R_390_IRELATIVE = 61 + }; + ++// ELF Relocation type for Sparc. ++enum { ++ R_SPARC_NONE = 0, ++ R_SPARC_8 = 1, ++ R_SPARC_16 = 2, ++ R_SPARC_32 = 3, ++ R_SPARC_DISP8 = 4, ++ R_SPARC_DISP16 = 5, ++ R_SPARC_DISP32 = 6, ++ R_SPARC_WDISP30 = 7, ++ R_SPARC_WDISP22 = 8, ++ R_SPARC_HI22 = 9, ++ R_SPARC_22 = 10, ++ R_SPARC_13 = 11, ++ R_SPARC_LO10 = 12, ++ R_SPARC_GOT10 = 13, ++ R_SPARC_GOT13 = 14, ++ R_SPARC_GOT22 = 15, ++ R_SPARC_PC10 = 16, ++ R_SPARC_PC22 = 17, ++ R_SPARC_WPLT30 = 18, ++ R_SPARC_COPY = 19, ++ R_SPARC_GLOB_DAT = 20, ++ R_SPARC_JMP_SLOT = 21, ++ R_SPARC_RELATIVE = 22, ++ R_SPARC_UA32 = 23, ++ R_SPARC_PLT32 = 24, ++ R_SPARC_HIPLT22 = 25, ++ R_SPARC_LOPLT10 = 26, ++ R_SPARC_PCPLT32 = 27, ++ R_SPARC_PCPLT22 = 28, ++ R_SPARC_PCPLT10 = 29, ++ R_SPARC_10 = 30, ++ R_SPARC_11 = 31, ++ R_SPARC_64 = 32, ++ R_SPARC_OLO10 = 33, ++ R_SPARC_HH22 = 34, ++ R_SPARC_HM10 = 35, ++ R_SPARC_LM22 = 36, ++ R_SPARC_PC_HH22 = 37, ++ R_SPARC_PC_HM10 = 38, ++ R_SPARC_PC_LM22 = 39, ++ R_SPARC_WDISP16 = 40, ++ R_SPARC_WDISP19 = 41, ++ R_SPARC_7 = 43, ++ R_SPARC_5 = 44, ++ R_SPARC_6 = 45, ++ R_SPARC_DISP64 = 46, ++ R_SPARC_PLT64 = 47, ++ R_SPARC_HIX22 = 48, ++ R_SPARC_LOX10 = 49, ++ R_SPARC_H44 = 50, ++ R_SPARC_M44 = 51, ++ R_SPARC_L44 = 52, ++ R_SPARC_REGISTER = 53, ++ R_SPARC_UA64 = 54, ++ R_SPARC_UA16 = 55 ++}; ++ + // Section header. + struct Elf32_Shdr { + Elf32_Word sh_name; // Section name (index into string table) diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198567-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198567-sparc.diff new file mode 100644 index 0000000..0ce6863 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198567-sparc.diff @@ -0,0 +1,21 @@ +Pull in r198567 from upstream llvm trunk (by Benjamin Kramer): + + SPARC: Make helper function static. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcAsmPrinter.cpp +=================================================================== +--- lib/Target/Sparc/SparcAsmPrinter.cpp ++++ lib/Target/Sparc/SparcAsmPrinter.cpp +@@ -130,8 +130,8 @@ static void EmitOR(MCStreamer &OutStreamer, MCOper + OutStreamer.EmitInstruction(ORInst); + } + +-void EmitADD(MCStreamer &OutStreamer, +- MCOperand &RS1, MCOperand &RS2, MCOperand &RD) ++static void EmitADD(MCStreamer &OutStreamer, ++ MCOperand &RS1, MCOperand &RS2, MCOperand &RD) + { + MCInst ADDInst; + ADDInst.setOpcode(SP::ADDrr); diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198580-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198580-sparc.diff new file mode 100644 index 0000000..e30cbb2 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198580-sparc.diff @@ -0,0 +1,460 @@ +Pull in r198580 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add ELF Object Writer for Sparc. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp +@@ -12,6 +12,7 @@ + //===----------------------------------------------------------------------===// + + #define DEBUG_TYPE "mccodeemitter" ++#include "SparcMCExpr.h" + #include "SparcMCTargetDesc.h" + #include "MCTargetDesc/SparcFixupKinds.h" + #include "llvm/MC/MCCodeEmitter.h" +@@ -92,6 +93,41 @@ getMachineOpValue(const MCInst &MI, const MCOperan + + assert(MO.isExpr()); + const MCExpr *Expr = MO.getExpr(); ++ if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Expr)) { ++ switch(SExpr->getKind()) { ++ default: assert(0 && "Unhandled sparc expression!"); break; ++ case SparcMCExpr::VK_Sparc_LO: ++ Fixups.push_back(MCFixup::Create(0, Expr, ++ (MCFixupKind)Sparc::fixup_sparc_lo10)); ++ break; ++ case SparcMCExpr::VK_Sparc_HI: ++ Fixups.push_back(MCFixup::Create(0, Expr, ++ (MCFixupKind)Sparc::fixup_sparc_hi22)); ++ break; ++ case SparcMCExpr::VK_Sparc_H44: ++ Fixups.push_back(MCFixup::Create(0, Expr, ++ (MCFixupKind)Sparc::fixup_sparc_h44)); ++ break; ++ case SparcMCExpr::VK_Sparc_M44: ++ Fixups.push_back(MCFixup::Create(0, Expr, ++ (MCFixupKind)Sparc::fixup_sparc_m44)); ++ break; ++ case SparcMCExpr::VK_Sparc_L44: ++ Fixups.push_back(MCFixup::Create(0, Expr, ++ (MCFixupKind)Sparc::fixup_sparc_l44)); ++ break; ++ case SparcMCExpr::VK_Sparc_HH: ++ Fixups.push_back(MCFixup::Create(0, Expr, ++ (MCFixupKind)Sparc::fixup_sparc_hh)); ++ break; ++ case SparcMCExpr::VK_Sparc_HM: ++ Fixups.push_back(MCFixup::Create(0, Expr, ++ (MCFixupKind)Sparc::fixup_sparc_hm)); ++ break; ++ } ++ return 0; ++ } ++ + int64_t Res; + if (Expr->EvaluateAsAbsolute(Res)) + return Res; +Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +@@ -89,6 +89,14 @@ static MCCodeGenInfo *createSparcV9MCCodeGenInfo(S + return X; + } + ++static MCStreamer *createMCStreamer(const Target &T, StringRef TT, ++ MCContext &Context, MCAsmBackend &MAB, ++ raw_ostream &OS, MCCodeEmitter *Emitter, ++ bool RelaxAll, bool NoExecStack) { ++ SparcTargetELFStreamer *S = new SparcTargetELFStreamer(); ++ return createELFStreamer(Context, S, MAB, OS, Emitter, RelaxAll, NoExecStack); ++} ++ + static MCStreamer * + createMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, + bool isVerboseAsm, bool useLoc, bool useCFI, +@@ -148,6 +156,13 @@ extern "C" void LLVMInitializeSparcTargetMC() { + TargetRegistry::RegisterMCAsmBackend(TheSparcV9Target, + createSparcAsmBackend); + ++ // Register the object streamer. ++ TargetRegistry::RegisterMCObjectStreamer(TheSparcTarget, ++ createMCStreamer); ++ TargetRegistry::RegisterMCObjectStreamer(TheSparcV9Target, ++ createMCStreamer); ++ ++ // Register the asm streamer. + TargetRegistry::RegisterAsmStreamer(TheSparcTarget, + createMCAsmStreamer); + TargetRegistry::RegisterAsmStreamer(TheSparcV9Target, +Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +@@ -10,6 +10,7 @@ + #include "llvm/MC/MCAsmBackend.h" + #include "MCTargetDesc/SparcMCTargetDesc.h" + #include "MCTargetDesc/SparcFixupKinds.h" ++#include "llvm/MC/MCELFObjectWriter.h" + #include "llvm/MC/MCFixupKindInfo.h" + #include "llvm/MC/MCObjectWriter.h" + #include "llvm/Support/TargetRegistry.h" +@@ -16,11 +17,43 @@ + + using namespace llvm; + ++static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) { ++ switch (Kind) { ++ default: ++ llvm_unreachable("Unknown fixup kind!"); ++ case FK_Data_1: ++ case FK_Data_2: ++ case FK_Data_4: ++ case FK_Data_8: ++ return Value; ++ case Sparc::fixup_sparc_call30: ++ return Value & 0x3fffffff; ++ case Sparc::fixup_sparc_br22: ++ return Value & 0x3fffff; ++ case Sparc::fixup_sparc_br19: ++ return Value & 0x1ffff; ++ case Sparc::fixup_sparc_hi22: ++ return (Value >> 10) & 0x3fffff; ++ case Sparc::fixup_sparc_lo10: ++ return Value & 0x3ff; ++ case Sparc::fixup_sparc_h44: ++ return (Value >> 22) & 0x3fffff; ++ case Sparc::fixup_sparc_m44: ++ return (Value >> 12) & 0x3ff; ++ case Sparc::fixup_sparc_l44: ++ return Value & 0xfff; ++ case Sparc::fixup_sparc_hh: ++ return (Value >> 42) & 0x3fffff; ++ case Sparc::fixup_sparc_hm: ++ return (Value >>32) & 0x3ff; ++ } ++} ++ + namespace { + class SparcAsmBackend : public MCAsmBackend { +- ++ const Target &TheTarget; + public: +- SparcAsmBackend(const Target &T) : MCAsmBackend() {} ++ SparcAsmBackend(const Target &T) : MCAsmBackend(), TheTarget(T) {} + + unsigned getNumFixupKinds() const { + return Sparc::NumTargetFixupKinds; +@@ -31,7 +64,14 @@ namespace { + // name offset bits flags + { "fixup_sparc_call30", 0, 30, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_sparc_br22", 0, 22, MCFixupKindInfo::FKF_IsPCRel }, +- { "fixup_sparc_br19", 0, 19, MCFixupKindInfo::FKF_IsPCRel } ++ { "fixup_sparc_br19", 0, 19, MCFixupKindInfo::FKF_IsPCRel }, ++ { "fixup_sparc_hi22", 0, 22, 0 }, ++ { "fixup_sparc_lo10", 0, 10, 0 }, ++ { "fixup_sparc_h44", 0, 22, 0 }, ++ { "fixup_sparc_m44", 0, 10, 0 }, ++ { "fixup_sparc_l44", 0, 12, 0 }, ++ { "fixup_sparc_hh", 0, 21, 0 }, ++ { "fixup_sparc_hm", 0, 10, 0 }, + }; + + if (Kind < FirstTargetFixupKind) +@@ -68,21 +108,38 @@ namespace { + OW->Write8(0); + return true; + } ++ ++ bool is64Bit() const { ++ StringRef name = TheTarget.getName(); ++ return name == "sparcv9"; ++ } + }; + + class ELFSparcAsmBackend : public SparcAsmBackend { ++ Triple::OSType OSType; + public: + ELFSparcAsmBackend(const Target &T, Triple::OSType OSType) : +- SparcAsmBackend(T) { } ++ SparcAsmBackend(T), OSType(OSType) { } + + void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + uint64_t Value) const { +- assert(0 && "applyFixup not implemented yet"); ++ ++ Value = adjustFixupValue(Fixup.getKind(), Value); ++ if (!Value) return; // Doesn't change encoding. ++ ++ unsigned Offset = Fixup.getOffset(); ++ ++ // For each byte of the fragment that the fixup touches, mask in the bits ++ // from the fixup value. The Value has been "split up" into the ++ // appropriate bitfields above. ++ for (unsigned i = 0; i != 4; ++i) ++ Data[Offset + i] |= uint8_t((Value >> ((4 - i - 1)*8)) & 0xff); ++ + } + + MCObjectWriter *createObjectWriter(raw_ostream &OS) const { +- assert(0 && "Object Writer not implemented yet"); +- return 0; ++ uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType); ++ return createSparcELFObjectWriter(OS, is64Bit(), OSABI); + } + + virtual bool doesSectionRequireSymbols(const MCSection &Section) const { +Index: lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h ++++ lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h +@@ -22,10 +22,32 @@ namespace llvm { + /// branches + fixup_sparc_br22, + +- /// fixup_sparc_br22 - 22-bit PC relative relocation for ++ /// fixup_sparc_br19 - 19-bit PC relative relocation for + /// branches on icc/xcc + fixup_sparc_br19, + ++ /// fixup_sparc_hi22 - 22-bit fixup corresponding to %hi(foo) ++ /// for sethi ++ fixup_sparc_hi22, ++ ++ /// fixup_sparc_lo10 - 10-bit fixup corresponding to %lo(foo) ++ fixup_sparc_lo10, ++ ++ /// fixup_sparc_h44 - 22-bit fixup corresponding to %h44(foo) ++ fixup_sparc_h44, ++ ++ /// fixup_sparc_m44 - 10-bit fixup corresponding to %m44(foo) ++ fixup_sparc_m44, ++ ++ /// fixup_sparc_l44 - 12-bit fixup corresponding to %l44(foo) ++ fixup_sparc_l44, ++ ++ /// fixup_sparc_hh - 22-bit fixup corresponding to %hh(foo) ++ fixup_sparc_hh, ++ ++ /// fixup_sparc_hm - 10-bit fixup corresponding to %hm(foo) ++ fixup_sparc_hm, ++ + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind +Index: lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp +@@ -0,0 +1,86 @@ ++//===-- SparcELFObjectWriter.cpp - Sparc ELF Writer -----------------------===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#include "MCTargetDesc/SparcMCTargetDesc.h" ++#include "MCTargetDesc/SparcFixupKinds.h" ++#include "llvm/ADT/STLExtras.h" ++#include "llvm/MC/MCELFObjectWriter.h" ++#include "llvm/MC/MCExpr.h" ++#include "llvm/MC/MCValue.h" ++#include "llvm/Support/ErrorHandling.h" ++ ++using namespace llvm; ++ ++namespace { ++ class SparcELFObjectWriter : public MCELFObjectTargetWriter { ++ public: ++ SparcELFObjectWriter(bool Is64Bit, uint8_t OSABI) ++ : MCELFObjectTargetWriter(Is64Bit, OSABI, ++ Is64Bit ? ELF::EM_SPARCV9 : ELF::EM_SPARC, ++ /*HasRelocationAddend*/ true) {} ++ ++ virtual ~SparcELFObjectWriter() {} ++ protected: ++ virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, ++ bool IsPCRel, bool IsRelocWithSymbol, ++ int64_t Addend) const; ++ ++ }; ++} ++ ++ ++unsigned SparcELFObjectWriter::GetRelocType(const MCValue &Target, ++ const MCFixup &Fixup, ++ bool IsPCRel, ++ bool IsRelocWithSymbol, ++ int64_t Addend) const { ++ if (IsPCRel) { ++ switch((unsigned)Fixup.getKind()) { ++ default: ++ llvm_unreachable("Unimplemented fixup -> relocation"); ++ case FK_Data_1: return ELF::R_SPARC_DISP8; ++ case FK_Data_2: return ELF::R_SPARC_DISP16; ++ case FK_Data_4: return ELF::R_SPARC_DISP32; ++ case FK_Data_8: return ELF::R_SPARC_DISP64; ++ case Sparc::fixup_sparc_call30: return ELF::R_SPARC_WDISP30; ++ case Sparc::fixup_sparc_br22: return ELF::R_SPARC_WDISP22; ++ case Sparc::fixup_sparc_br19: return ELF::R_SPARC_WDISP19; ++ } ++ } ++ ++ switch((unsigned)Fixup.getKind()) { ++ default: ++ llvm_unreachable("Unimplemented fixup -> relocation"); ++ case FK_Data_1: return ELF::R_SPARC_8; ++ case FK_Data_2: return ((Fixup.getOffset() % 2) ++ ? ELF::R_SPARC_UA16 ++ : ELF::R_SPARC_16); ++ case FK_Data_4: return ((Fixup.getOffset() % 4) ++ ? ELF::R_SPARC_UA32 ++ : ELF::R_SPARC_32); ++ case FK_Data_8: return ((Fixup.getOffset() % 8) ++ ? ELF::R_SPARC_UA64 ++ : ELF::R_SPARC_64); ++ case Sparc::fixup_sparc_hi22: return ELF::R_SPARC_HI22; ++ case Sparc::fixup_sparc_lo10: return ELF::R_SPARC_LO10; ++ case Sparc::fixup_sparc_h44: return ELF::R_SPARC_H44; ++ case Sparc::fixup_sparc_m44: return ELF::R_SPARC_M44; ++ case Sparc::fixup_sparc_l44: return ELF::R_SPARC_L44; ++ case Sparc::fixup_sparc_hh: return ELF::R_SPARC_HH22; ++ case Sparc::fixup_sparc_hm: return ELF::R_SPARC_HM10; ++ } ++ return ELF::R_SPARC_NONE; ++} ++ ++MCObjectWriter *llvm::createSparcELFObjectWriter(raw_ostream &OS, ++ bool Is64Bit, ++ uint8_t OSABI) { ++ MCELFObjectTargetWriter *MOTW = new SparcELFObjectWriter(Is64Bit, OSABI); ++ return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false); ++} +Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h ++++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h +@@ -14,15 +14,19 @@ + #ifndef SPARCMCTARGETDESC_H + #define SPARCMCTARGETDESC_H + ++#include "llvm/Support/DataTypes.h" ++ + namespace llvm { + class MCAsmBackend; + class MCCodeEmitter; + class MCContext; + class MCInstrInfo; ++class MCObjectWriter; + class MCRegisterInfo; + class MCSubtargetInfo; + class Target; + class StringRef; ++class raw_ostream; + + extern Target TheSparcTarget; + extern Target TheSparcV9Target; +@@ -35,7 +39,9 @@ MCAsmBackend *createSparcAsmBackend(const Target & + const MCRegisterInfo &MRI, + StringRef TT, + StringRef CPU); +- ++MCObjectWriter *createSparcELFObjectWriter(raw_ostream &OS, ++ bool Is64Bit, ++ uint8_t OSABI); + } // End llvm namespace + + // Defines symbolic names for Sparc registers. This defines a mapping from +Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +@@ -70,15 +70,67 @@ void SparcMCExpr::PrintImpl(raw_ostream &OS) const + bool + SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const { +- assert(0 && "FIXME: Implement SparcMCExpr::EvaluateAsRelocatableImpl"); + return getSubExpr()->EvaluateAsRelocatable(Res, *Layout); + } + ++static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) { ++ assert(0 && "Implement fixELFSymbolsInTLSFixupsImpl!"); ++} + + void SparcMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { +- assert(0 && "FIXME: Implement SparcMCExpr::fixELFSymbolsInTLSFixups"); ++ switch(getKind()) { ++ default: return; ++ case VK_Sparc_TLS_GD_HI22: ++ case VK_Sparc_TLS_GD_LO10: ++ case VK_Sparc_TLS_GD_ADD: ++ case VK_Sparc_TLS_GD_CALL: ++ case VK_Sparc_TLS_LDM_HI22: ++ case VK_Sparc_TLS_LDM_LO10: ++ case VK_Sparc_TLS_LDM_ADD: ++ case VK_Sparc_TLS_LDM_CALL: ++ case VK_Sparc_TLS_LDO_HIX22: ++ case VK_Sparc_TLS_LDO_LOX10: ++ case VK_Sparc_TLS_LDO_ADD: ++ case VK_Sparc_TLS_IE_HI22: ++ case VK_Sparc_TLS_IE_LO10: ++ case VK_Sparc_TLS_IE_LD: ++ case VK_Sparc_TLS_IE_LDX: ++ case VK_Sparc_TLS_IE_ADD: ++ case VK_Sparc_TLS_LE_HIX22: ++ case VK_Sparc_TLS_LE_LOX10: break; ++ } ++ fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm); + } + ++// FIXME: This basically copies MCObjectStreamer::AddValueSymbols. Perhaps ++// that method should be made public? ++// FIXME: really do above: now that at least three other backends are using it. ++static void AddValueSymbolsImpl(const MCExpr *Value, MCAssembler *Asm) { ++ switch (Value->getKind()) { ++ case MCExpr::Target: ++ llvm_unreachable("Can't handle nested target expr!"); ++ break; ++ ++ case MCExpr::Constant: ++ break; ++ ++ case MCExpr::Binary: { ++ const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value); ++ AddValueSymbolsImpl(BE->getLHS(), Asm); ++ AddValueSymbolsImpl(BE->getRHS(), Asm); ++ break; ++ } ++ ++ case MCExpr::SymbolRef: ++ Asm->getOrCreateSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol()); ++ break; ++ ++ case MCExpr::Unary: ++ AddValueSymbolsImpl(cast<MCUnaryExpr>(Value)->getSubExpr(), Asm); ++ break; ++ } ++} ++ + void SparcMCExpr::AddValueSymbols(MCAssembler *Asm) const { +- assert(0 && "FIXME: Implement SparcMCExpr::AddValueSymbols"); ++ AddValueSymbolsImpl(getSubExpr(), Asm); + } +Index: lib/Target/Sparc/MCTargetDesc/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/CMakeLists.txt ++++ lib/Target/Sparc/MCTargetDesc/CMakeLists.txt +@@ -1,5 +1,6 @@ + add_llvm_library(LLVMSparcDesc + SparcAsmBackend.cpp ++ SparcELFObjectWriter.cpp + SparcMCAsmInfo.cpp + SparcMCCodeEmitter.cpp + SparcMCTargetDesc.cpp diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198591-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198591-sparc.diff new file mode 100644 index 0000000..056cb34 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198591-sparc.diff @@ -0,0 +1,762 @@ +Pull in r198591 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add initial implementation of disassembler for sparc + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcInstrFormats.td +=================================================================== +--- lib/Target/Sparc/SparcInstrFormats.td ++++ lib/Target/Sparc/SparcInstrFormats.td +@@ -12,6 +12,7 @@ class InstSP<dag outs, dag ins, string asmstr, lis + field bits<32> Inst; + + let Namespace = "SP"; ++ let Size = 4; + + bits<2> op; + let Inst{31-30} = op; // Top two bits are the 'op' field +@@ -20,6 +21,9 @@ class InstSP<dag outs, dag ins, string asmstr, lis + dag InOperandList = ins; + let AsmString = asmstr; + let Pattern = pattern; ++ ++ let DecoderNamespace = "Sparc"; ++ field bits<32> SoftFail = 0; + } + + //===----------------------------------------------------------------------===// +@@ -58,6 +62,27 @@ class F2_2<bits<3> op2Val, dag outs, dag ins, stri + let Inst{28-25} = cond; + } + ++class F2_3<bits<3> op2Val, bits<2> ccVal, dag outs, dag ins, string asmstr, ++ list<dag> pattern> ++ : InstSP<outs, ins, asmstr, pattern> { ++ bit annul; ++ bits<4> cond; ++ bit pred; ++ bits<19> imm19; ++ ++ let op = 0; // op = 0 ++ ++ bit annul = 0; // currently unused ++ let pred = 1; // default is predict taken ++ ++ let Inst{29} = annul; ++ let Inst{28-25} = cond; ++ let Inst{24-22} = op2Val; ++ let Inst{21-20} = ccVal; ++ let Inst{19} = pred; ++ let Inst{18-0} = imm19; ++} ++ + //===----------------------------------------------------------------------===// + // Format #3 instruction classes in the Sparc + //===----------------------------------------------------------------------===// +Index: lib/Target/Sparc/LLVMBuild.txt +=================================================================== +--- lib/Target/Sparc/LLVMBuild.txt ++++ lib/Target/Sparc/LLVMBuild.txt +@@ -16,13 +16,15 @@ + ;===------------------------------------------------------------------------===; + + [common] +-subdirectories = AsmParser InstPrinter MCTargetDesc TargetInfo ++subdirectories = AsmParser Disassembler InstPrinter MCTargetDesc TargetInfo + + [component_0] + type = TargetGroup + name = Sparc + parent = Target ++has_asmparser = 1 + has_asmprinter = 1 ++has_disassembler = 1 + has_jit = 1 + + [component_1] +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -230,13 +230,13 @@ def FCC_O : FCC_VAL<29>; // Ordered + multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode, + RegisterClass RC, ValueType Ty, Operand immOp> { + def rr : F3_1<2, Op3Val, +- (outs RC:$dst), (ins RC:$b, RC:$c), +- !strconcat(OpcStr, " $b, $c, $dst"), +- [(set Ty:$dst, (OpNode Ty:$b, Ty:$c))]>; ++ (outs RC:$rd), (ins RC:$rs1, RC:$rs2), ++ !strconcat(OpcStr, " $rs1, $rs2, $rd"), ++ [(set Ty:$rd, (OpNode Ty:$rs1, Ty:$rs2))]>; + def ri : F3_2<2, Op3Val, +- (outs RC:$dst), (ins RC:$b, immOp:$c), +- !strconcat(OpcStr, " $b, $c, $dst"), +- [(set Ty:$dst, (OpNode Ty:$b, (Ty simm13:$c)))]>; ++ (outs RC:$rd), (ins RC:$rs1, immOp:$simm13), ++ !strconcat(OpcStr, " $rs1, $simm13, $rd"), ++ [(set Ty:$rd, (OpNode Ty:$rs1, (Ty simm13:$simm13)))]>; + } + + /// F3_12np multiclass - Define a normal F3_1/F3_2 pattern in one shot, with no +@@ -243,11 +243,11 @@ multiclass F3_12<string OpcStr, bits<6> Op3Val, SD + /// pattern. + multiclass F3_12np<string OpcStr, bits<6> Op3Val> { + def rr : F3_1<2, Op3Val, +- (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), +- !strconcat(OpcStr, " $b, $c, $dst"), []>; ++ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2), ++ !strconcat(OpcStr, " $rs1, $rs2, $rd"), []>; + def ri : F3_2<2, Op3Val, +- (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), +- !strconcat(OpcStr, " $b, $c, $dst"), []>; ++ (outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13), ++ !strconcat(OpcStr, " $rs1, $simm13, $rd"), []>; + } + + //===----------------------------------------------------------------------===// +@@ -488,31 +488,31 @@ let rd = 0, imm22 = 0 in + defm AND : F3_12<"and", 0b000001, and, IntRegs, i32, i32imm>; + + def ANDNrr : F3_1<2, 0b000101, +- (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), +- "andn $b, $c, $dst", +- [(set i32:$dst, (and i32:$b, (not i32:$c)))]>; ++ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2), ++ "andn $rs1, $rs2, $rd", ++ [(set i32:$rd, (and i32:$rs1, (not i32:$rs2)))]>; + def ANDNri : F3_2<2, 0b000101, +- (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), +- "andn $b, $c, $dst", []>; ++ (outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13), ++ "andn $rs1, $simm13, $rd", []>; + + defm OR : F3_12<"or", 0b000010, or, IntRegs, i32, i32imm>; + + def ORNrr : F3_1<2, 0b000110, +- (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), +- "orn $b, $c, $dst", +- [(set i32:$dst, (or i32:$b, (not i32:$c)))]>; ++ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2), ++ "orn $rs1, $rs2, $rd", ++ [(set i32:$rd, (or i32:$rs1, (not i32:$rs2)))]>; + def ORNri : F3_2<2, 0b000110, +- (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), +- "orn $b, $c, $dst", []>; ++ (outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13), ++ "orn $rs1, $simm13, $rd", []>; + defm XOR : F3_12<"xor", 0b000011, xor, IntRegs, i32, i32imm>; + + def XNORrr : F3_1<2, 0b000111, +- (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), +- "xnor $b, $c, $dst", +- [(set i32:$dst, (not (xor i32:$b, i32:$c)))]>; ++ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2), ++ "xnor $rs1, $rs2, $rd", ++ [(set i32:$rd, (not (xor i32:$rs1, i32:$rs2)))]>; + def XNORri : F3_2<2, 0b000111, +- (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), +- "xnor $b, $c, $dst", []>; ++ (outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13), ++ "xnor $rs1, $simm13, $rd", []>; + + // Section B.12 - Shift Instructions, p. 107 + defm SLL : F3_12<"sll", 0b100101, shl, IntRegs, i32, i32imm>; +@@ -545,21 +545,15 @@ let Defs = [ICC] in + + let Defs = [ICC], rd = 0 in { + def CMPrr : F3_1<2, 0b010100, +- (outs), (ins IntRegs:$b, IntRegs:$c), +- "cmp $b, $c", +- [(SPcmpicc i32:$b, i32:$c)]>; ++ (outs), (ins IntRegs:$rs1, IntRegs:$rs2), ++ "cmp $rs1, $rs2", ++ [(SPcmpicc i32:$rs1, i32:$rs2)]>; + def CMPri : F3_2<2, 0b010100, +- (outs), (ins IntRegs:$b, i32imm:$c), +- "cmp $b, $c", +- [(SPcmpicc i32:$b, (i32 simm13:$c))]>; ++ (outs), (ins IntRegs:$rs1, i32imm:$simm13), ++ "cmp $rs1, $simm13", ++ [(SPcmpicc i32:$rs1, (i32 simm13:$simm13))]>; + } + +-let Uses = [ICC], Defs = [ICC] in +- def SUBXCCrr: F3_1<2, 0b011100, +- (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), +- "subxcc $b, $c, $dst", []>; +- +- + // Section B.18 - Multiply Instructions, p. 113 + let Defs = [Y] in { + defm UMUL : F3_12np<"umul", 0b001010>; +@@ -858,7 +852,7 @@ let Defs = [FCC] in { + //===----------------------------------------------------------------------===// + // Instructions for Thread Local Storage(TLS). + //===----------------------------------------------------------------------===// +- ++let isCodeGenOnly = 1, isAsmParserOnly = 1 in { + def TLS_ADDrr : F3_1<2, 0b000000, + (outs IntRegs:$rd), + (ins IntRegs:$rs1, IntRegs:$rs2, TLSSym:$sym), +@@ -882,6 +876,7 @@ let Uses = [O6], isCall = 1, hasDelaySlot = 1 in + let op = 1; + let Inst{29-0} = disp; + } ++} + + //===----------------------------------------------------------------------===// + // V9 Instructions +Index: lib/Target/Sparc/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/CMakeLists.txt ++++ lib/Target/Sparc/CMakeLists.txt +@@ -3,6 +3,7 @@ set(LLVM_TARGET_DEFINITIONS Sparc.td) + tablegen(LLVM SparcGenRegisterInfo.inc -gen-register-info) + tablegen(LLVM SparcGenInstrInfo.inc -gen-instr-info) + tablegen(LLVM SparcGenCodeEmitter.inc -gen-emitter) ++tablegen(LLVM SparcGenDisassemblerTables.inc -gen-disassembler) + tablegen(LLVM SparcGenMCCodeEmitter.inc -gen-emitter -mc-emitter) + tablegen(LLVM SparcGenAsmWriter.inc -gen-asm-writer) + tablegen(LLVM SparcGenAsmMatcher.inc -gen-asm-matcher) +@@ -34,3 +35,4 @@ add_subdirectory(TargetInfo) + add_subdirectory(MCTargetDesc) + add_subdirectory(InstPrinter) + add_subdirectory(AsmParser) ++add_subdirectory(Disassembler) +Index: lib/Target/Sparc/Disassembler/SparcDisassembler.cpp +=================================================================== +--- lib/Target/Sparc/Disassembler/SparcDisassembler.cpp ++++ lib/Target/Sparc/Disassembler/SparcDisassembler.cpp +@@ -0,0 +1,228 @@ ++//===- SparcDisassembler.cpp - Disassembler for Sparc -----------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++// ++// This file is part of the Sparc Disassembler. ++// ++//===----------------------------------------------------------------------===// ++ ++#define DEBUG_TYPE "sparc-disassembler" ++ ++#include "Sparc.h" ++#include "SparcRegisterInfo.h" ++#include "SparcSubtarget.h" ++#include "llvm/MC/MCDisassembler.h" ++#include "llvm/MC/MCFixedLenDisassembler.h" ++#include "llvm/Support/MemoryObject.h" ++#include "llvm/Support/TargetRegistry.h" ++ ++using namespace llvm; ++ ++typedef MCDisassembler::DecodeStatus DecodeStatus; ++ ++namespace { ++ ++/// SparcDisassembler - a disassembler class for Sparc. ++class SparcDisassembler : public MCDisassembler { ++public: ++ /// Constructor - Initializes the disassembler. ++ /// ++ SparcDisassembler(const MCSubtargetInfo &STI, const MCRegisterInfo *Info) : ++ MCDisassembler(STI), RegInfo(Info) ++ {} ++ virtual ~SparcDisassembler() {} ++ ++ const MCRegisterInfo *getRegInfo() const { return RegInfo.get(); } ++ ++ /// getInstruction - See MCDisassembler. ++ virtual DecodeStatus getInstruction(MCInst &instr, ++ uint64_t &size, ++ const MemoryObject ®ion, ++ uint64_t address, ++ raw_ostream &vStream, ++ raw_ostream &cStream) const; ++private: ++ OwningPtr<const MCRegisterInfo> RegInfo; ++}; ++ ++} ++ ++namespace llvm { ++ extern Target TheSparcTarget, TheSparcV9Target; ++} ++ ++static MCDisassembler *createSparcDisassembler( ++ const Target &T, ++ const MCSubtargetInfo &STI) { ++ return new SparcDisassembler(STI, T.createMCRegInfo("")); ++} ++ ++ ++extern "C" void LLVMInitializeSparcDisassembler() { ++ // Register the disassembler. ++ TargetRegistry::RegisterMCDisassembler(TheSparcTarget, ++ createSparcDisassembler); ++ TargetRegistry::RegisterMCDisassembler(TheSparcV9Target, ++ createSparcDisassembler); ++} ++ ++ ++ ++static const unsigned IntRegDecoderTable[] = { ++ SP::G0, SP::G1, SP::G2, SP::G3, ++ SP::G4, SP::G5, SP::G6, SP::G7, ++ SP::O0, SP::O1, SP::O2, SP::O3, ++ SP::O4, SP::O5, SP::O6, SP::O7, ++ SP::L0, SP::L1, SP::L2, SP::L3, ++ SP::L4, SP::L5, SP::L6, SP::L7, ++ SP::I0, SP::I1, SP::I2, SP::I3, ++ SP::I4, SP::I5, SP::I6, SP::I7 }; ++ ++static const unsigned FPRegDecoderTable[] = { ++ SP::F0, SP::F1, SP::F2, SP::F3, ++ SP::F4, SP::F5, SP::F6, SP::F7, ++ SP::F8, SP::F9, SP::F10, SP::F11, ++ SP::F12, SP::F13, SP::F14, SP::F15, ++ SP::F16, SP::F17, SP::F18, SP::F19, ++ SP::F20, SP::F21, SP::F22, SP::F23, ++ SP::F24, SP::F25, SP::F26, SP::F27, ++ SP::F28, SP::F29, SP::F30, SP::F31 }; ++ ++static const unsigned DFPRegDecoderTable[] = { ++ SP::D0, SP::D16, SP::D1, SP::D17, ++ SP::D2, SP::D18, SP::D3, SP::D19, ++ SP::D4, SP::D20, SP::D5, SP::D21, ++ SP::D6, SP::D22, SP::D7, SP::D23, ++ SP::D8, SP::D24, SP::D9, SP::D25, ++ SP::D10, SP::D26, SP::D11, SP::D27, ++ SP::D12, SP::D28, SP::D13, SP::D29, ++ SP::D14, SP::D30, SP::D15, SP::D31 }; ++ ++static const unsigned QFPRegDecoderTable[] = { ++ SP::Q0, SP::Q8, -1, -1, ++ SP::Q1, SP::Q9, -1, -1, ++ SP::Q2, SP::Q10, -1, -1, ++ SP::Q3, SP::Q11, -1, -1, ++ SP::Q4, SP::Q12, -1, -1, ++ SP::Q5, SP::Q13, -1, -1, ++ SP::Q6, SP::Q14, -1, -1, ++ SP::Q7, SP::Q15, -1, -1 } ; ++ ++static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst, ++ unsigned RegNo, ++ uint64_t Address, ++ const void *Decoder) { ++ if (RegNo > 31) ++ return MCDisassembler::Fail; ++ unsigned Reg = IntRegDecoderTable[RegNo]; ++ Inst.addOperand(MCOperand::CreateReg(Reg)); ++ return MCDisassembler::Success; ++} ++ ++static DecodeStatus DecodeI64RegsRegisterClass(MCInst &Inst, ++ unsigned RegNo, ++ uint64_t Address, ++ const void *Decoder) { ++ if (RegNo > 31) ++ return MCDisassembler::Fail; ++ unsigned Reg = IntRegDecoderTable[RegNo]; ++ Inst.addOperand(MCOperand::CreateReg(Reg)); ++ return MCDisassembler::Success; ++} ++ ++ ++static DecodeStatus DecodeFPRegsRegisterClass(MCInst &Inst, ++ unsigned RegNo, ++ uint64_t Address, ++ const void *Decoder) { ++ if (RegNo > 31) ++ return MCDisassembler::Fail; ++ unsigned Reg = FPRegDecoderTable[RegNo]; ++ Inst.addOperand(MCOperand::CreateReg(Reg)); ++ return MCDisassembler::Success; ++} ++ ++ ++static DecodeStatus DecodeDFPRegsRegisterClass(MCInst &Inst, ++ unsigned RegNo, ++ uint64_t Address, ++ const void *Decoder) { ++ if (RegNo > 31) ++ return MCDisassembler::Fail; ++ unsigned Reg = DFPRegDecoderTable[RegNo]; ++ Inst.addOperand(MCOperand::CreateReg(Reg)); ++ return MCDisassembler::Success; ++} ++ ++ ++static DecodeStatus DecodeQFPRegsRegisterClass(MCInst &Inst, ++ unsigned RegNo, ++ uint64_t Address, ++ const void *Decoder) { ++ if (RegNo > 31) ++ return MCDisassembler::Fail; ++ ++ unsigned Reg = QFPRegDecoderTable[RegNo]; ++ if (Reg == (unsigned)-1) ++ return MCDisassembler::Fail; ++ Inst.addOperand(MCOperand::CreateReg(Reg)); ++ return MCDisassembler::Success; ++} ++ ++ ++#include "SparcGenDisassemblerTables.inc" ++ ++/// readInstruction - read four bytes from the MemoryObject ++/// and return 32 bit word. ++static DecodeStatus readInstruction32(const MemoryObject ®ion, ++ uint64_t address, ++ uint64_t &size, ++ uint32_t &insn) { ++ uint8_t Bytes[4]; ++ ++ // We want to read exactly 4 Bytes of data. ++ if (region.readBytes(address, 4, Bytes) == -1) { ++ size = 0; ++ return MCDisassembler::Fail; ++ } ++ ++ // Encoded as a big-endian 32-bit word in the stream. ++ insn = (Bytes[3] << 0) | ++ (Bytes[2] << 8) | ++ (Bytes[1] << 16) | ++ (Bytes[0] << 24); ++ ++ return MCDisassembler::Success; ++} ++ ++ ++DecodeStatus ++SparcDisassembler::getInstruction(MCInst &instr, ++ uint64_t &Size, ++ const MemoryObject &Region, ++ uint64_t Address, ++ raw_ostream &vStream, ++ raw_ostream &cStream) const { ++ uint32_t Insn; ++ ++ DecodeStatus Result = readInstruction32(Region, Address, Size, Insn); ++ if (Result == MCDisassembler::Fail) ++ return MCDisassembler::Fail; ++ ++ ++ // Calling the auto-generated decoder function. ++ Result = decodeInstruction(DecoderTableSparc32, instr, Insn, Address, ++ this, STI); ++ ++ if (Result != MCDisassembler::Fail) { ++ Size = 4; ++ return Result; ++ } ++ ++ return MCDisassembler::Fail; ++} +Index: lib/Target/Sparc/Disassembler/LLVMBuild.txt +=================================================================== +--- lib/Target/Sparc/Disassembler/LLVMBuild.txt ++++ lib/Target/Sparc/Disassembler/LLVMBuild.txt +@@ -0,0 +1,23 @@ ++;===- ./lib/Target/Sparc/Disassembler/LLVMBuild.txt ------------*- Conf -*--===; ++; ++; The LLVM Compiler Infrastructure ++; ++; This file is distributed under the University of Illinois Open Source ++; License. See LICENSE.TXT for details. ++; ++;===------------------------------------------------------------------------===; ++; ++; This is an LLVMBuild description file for the components in this subdirectory. ++; ++; For more information on the LLVMBuild system, please see: ++; ++; http://llvm.org/docs/LLVMBuild.html ++; ++;===------------------------------------------------------------------------===; ++ ++[component_0] ++type = Library ++name = SparcDisassembler ++parent = Sparc ++required_libraries = MC Support SparcInfo ++add_to_library_groups = Sparc +Index: lib/Target/Sparc/Disassembler/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/Disassembler/CMakeLists.txt ++++ lib/Target/Sparc/Disassembler/CMakeLists.txt +@@ -0,0 +1,12 @@ ++add_llvm_library(LLVMSparcDisassembler ++ SparcDisassembler.cpp ++ ) ++ ++# workaround for hanging compilation on MSVC9 and 10 ++if( MSVC_VERSION EQUAL 1400 OR MSVC_VERSION EQUAL 1500 ++ OR MSVC_VERSION EQUAL 1600 ) ++set_property( ++ SOURCE SparcDisassembler.cpp ++ PROPERTY COMPILE_FLAGS "/Od" ++ ) ++endif() +Index: lib/Target/Sparc/Disassembler/Makefile +=================================================================== +--- lib/Target/Sparc/Disassembler/Makefile ++++ lib/Target/Sparc/Disassembler/Makefile +@@ -0,0 +1,16 @@ ++##===- lib/Target/Sparc/Disassembler/Makefile --------------*- Makefile -*-===## ++# ++# The LLVM Compiler Infrastructure ++# ++# This file is distributed under the University of Illinois Open Source ++# License. See LICENSE.TXT for details. ++# ++##===----------------------------------------------------------------------===## ++ ++LEVEL = ../../../.. ++LIBRARYNAME = LLVMSparcDisassembler ++ ++# Hack: we need to include 'main' Sparc target directory to grab private headers ++CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. ++ ++include $(LEVEL)/Makefile.common +Index: lib/Target/Sparc/Makefile +=================================================================== +--- lib/Target/Sparc/Makefile ++++ lib/Target/Sparc/Makefile +@@ -14,11 +14,11 @@ TARGET = Sparc + # Make sure that tblgen is run, first thing. + BUILT_SOURCES = SparcGenRegisterInfo.inc SparcGenInstrInfo.inc \ + SparcGenAsmWriter.inc SparcGenAsmMatcher.inc \ +- SparcGenDAGISel.inc \ ++ SparcGenDAGISel.inc SparcGenDisassemblerTables.inc \ + SparcGenSubtargetInfo.inc SparcGenCallingConv.inc \ + SparcGenCodeEmitter.inc SparcGenMCCodeEmitter.inc + +-DIRS = InstPrinter AsmParser TargetInfo MCTargetDesc ++DIRS = InstPrinter AsmParser Disassembler TargetInfo MCTargetDesc + + include $(LEVEL)/Makefile.common + +Index: lib/Target/Sparc/SparcInstr64Bit.td +=================================================================== +--- lib/Target/Sparc/SparcInstr64Bit.td ++++ lib/Target/Sparc/SparcInstr64Bit.td +@@ -141,6 +141,7 @@ def : Pat<(i64 imm:$val), + let Predicates = [Is64Bit] in { + + // Register-register instructions. ++let isCodeGenOnly = 1 in { + defm ANDX : F3_12<"and", 0b000001, and, I64Regs, i64, i64imm>; + defm ORX : F3_12<"or", 0b000010, or, I64Regs, i64, i64imm>; + defm XORX : F3_12<"xor", 0b000011, xor, I64Regs, i64, i64imm>; +@@ -161,8 +162,6 @@ def XNORXrr : F3_1<2, 0b000111, + defm ADDX : F3_12<"add", 0b000000, add, I64Regs, i64, i64imm>; + defm SUBX : F3_12<"sub", 0b000100, sub, I64Regs, i64, i64imm>; + +-def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>; +- + def TLS_ADDXrr : F3_1<2, 0b000000, (outs I64Regs:$rd), + (ins I64Regs:$rs1, I64Regs:$rs2, TLSSym:$sym), + "add $rs1, $rs2, $rd, $sym", +@@ -169,18 +168,17 @@ def TLS_ADDXrr : F3_1<2, 0b000000, (outs I64Regs:$ + [(set i64:$rd, + (tlsadd i64:$rs1, i64:$rs2, tglobaltlsaddr:$sym))]>; + +-// Register-immediate instructions. +- +-def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMPri $a, (as_i32imm $b))>; +- +-def : Pat<(ctpop i64:$src), (POPCrr $src)>; +- + // "LEA" form of add +-let isCodeGenOnly = 1 in + def LEAX_ADDri : F3_2<2, 0b000000, + (outs I64Regs:$dst), (ins MEMri:$addr), + "add ${addr:arith}, $dst", + [(set iPTR:$dst, ADDRri:$addr)]>; ++} ++ ++def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>; ++def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMPri $a, (as_i32imm $b))>; ++def : Pat<(ctpop i64:$src), (POPCrr $src)>; ++ + } // Predicates = [Is64Bit] + + +@@ -245,7 +243,7 @@ def LDXri : F3_2<3, 0b001011, + (outs I64Regs:$dst), (ins MEMri:$addr), + "ldx [$addr], $dst", + [(set i64:$dst, (load ADDRri:$addr))]>; +-let mayLoad = 1 in ++let mayLoad = 1, isCodeGenOnly = 1, isAsmParserOnly = 1 in + def TLS_LDXrr : F3_1<3, 0b001011, + (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym), + "ldx [$addr], $dst, $sym", +@@ -278,11 +276,11 @@ def : Pat<(i64 (extloadi32 ADDRrr:$addr)), (LDrr + def : Pat<(i64 (extloadi32 ADDRri:$addr)), (LDri ADDRri:$addr)>; + + // Sign-extending load of i32 into i64 is a new SPARC v9 instruction. +-def LDSWrr : F3_1<3, 0b001011, ++def LDSWrr : F3_1<3, 0b001000, + (outs I64Regs:$dst), (ins MEMrr:$addr), + "ldsw [$addr], $dst", + [(set i64:$dst, (sextloadi32 ADDRrr:$addr))]>; +-def LDSWri : F3_2<3, 0b001011, ++def LDSWri : F3_2<3, 0b001000, + (outs I64Regs:$dst), (ins MEMri:$addr), + "ldsw [$addr], $dst", + [(set i64:$dst, (sextloadi32 ADDRri:$addr))]>; +@@ -289,13 +287,13 @@ def : Pat<(i64 (extloadi32 ADDRri:$addr)), (LDri + + // 64-bit stores. + def STXrr : F3_1<3, 0b001110, +- (outs), (ins MEMrr:$addr, I64Regs:$src), +- "stx $src, [$addr]", +- [(store i64:$src, ADDRrr:$addr)]>; ++ (outs), (ins MEMrr:$addr, I64Regs:$rd), ++ "stx $rd, [$addr]", ++ [(store i64:$rd, ADDRrr:$addr)]>; + def STXri : F3_2<3, 0b001110, +- (outs), (ins MEMri:$addr, I64Regs:$src), +- "stx $src, [$addr]", +- [(store i64:$src, ADDRri:$addr)]>; ++ (outs), (ins MEMri:$addr, I64Regs:$rd), ++ "stx $rd, [$addr]", ++ [(store i64:$rd, ADDRri:$addr)]>; + + // Truncating stores from i64 are identical to the i32 stores. + def : Pat<(truncstorei8 i64:$src, ADDRrr:$addr), (STBrr ADDRrr:$addr, $src)>; +@@ -315,6 +313,15 @@ def : Pat<(store (i64 0), ADDRri:$dst), (STXri ADD + //===----------------------------------------------------------------------===// + // 64-bit Conditionals. + //===----------------------------------------------------------------------===// ++ ++// Conditional branch class on %xcc: ++class XBranchSP<dag ins, string asmstr, list<dag> pattern> ++ : F2_3<0b001, 0b10, (outs), ins, asmstr, pattern> { ++ let isBranch = 1; ++ let isTerminator = 1; ++ let hasDelaySlot = 1; ++} ++ + // + // Flag-setting instructions like subcc and addcc set both icc and xcc flags. + // The icc flags correspond to the 32-bit result, and the xcc are for the +@@ -326,7 +333,7 @@ def : Pat<(store (i64 0), ADDRri:$dst), (STXri ADD + let Predicates = [Is64Bit] in { + + let Uses = [ICC] in +-def BPXCC : BranchSP<(ins brtarget:$imm22, CCOp:$cond), ++def BPXCC : XBranchSP<(ins brtarget:$imm22, CCOp:$cond), + "b$cond %xcc, $imm22", + [(SPbrxcc bb:$imm22, imm:$cond)]>; + +@@ -409,7 +416,7 @@ def : Pat<(SPselectfcc (i64 simm11:$t), i64:$f, im + + + // 64 bit SETHI +-let Predicates = [Is64Bit] in { ++let Predicates = [Is64Bit], isCodeGenOnly = 1 in { + def SETHIXi : F2_1<0b100, + (outs IntRegs:$rd), (ins i64imm:$imm22), + "sethi $imm22, $rd", +Index: test/MC/Disassembler/Sparc/lit.local.cfg +=================================================================== +--- test/MC/Disassembler/Sparc/lit.local.cfg ++++ test/MC/Disassembler/Sparc/lit.local.cfg +@@ -0,0 +1,4 @@ ++targets = set(config.root.targets_to_build.split()) ++if not 'Sparc' in targets: ++ config.unsupported = True ++ +Index: test/MC/Disassembler/Sparc/sparc.txt +=================================================================== +--- test/MC/Disassembler/Sparc/sparc.txt ++++ test/MC/Disassembler/Sparc/sparc.txt +@@ -0,0 +1,82 @@ ++# RUN: llvm-mc --disassemble %s -triple=sparc-unknown-linux | FileCheck %s ++ ++# CHECK: add %g0, %g0, %g0 ++0x80 0x00 0x00 0x00 ++ ++# CHECK: add %g1, %g2, %g3 ++0x86 0x00 0x40 0x02 ++ ++# CHECK: add %o0, %o1, %l0 ++0xa0 0x02 0x00 0x09 ++ ++# CHECK: add %o0, 10, %l0 ++0xa0 0x02 0x20 0x0a ++ ++# CHECK: addcc %g1, %g2, %g3 ++0x86 0x80 0x40 0x02 ++ ++# CHECK: addxcc %g1, %g2, %g3 ++0x86 0xc0 0x40 0x02 ++ ++# CHECK: udiv %g1, %g2, %g3 ++0x86 0x70 0x40 0x02 ++ ++# CHECK: sdiv %g1, %g2, %g3 ++0x86 0x78 0x40 0x02 ++ ++# CHECK: and %g1, %g2, %g3 ++0x86 0x08 0x40 0x02 ++ ++# CHECK: andn %g1, %g2, %g3 ++0x86 0x28 0x40 0x02 ++ ++# CHECK: or %g1, %g2, %g3 ++0x86 0x10 0x40 0x02 ++ ++# CHECK: orn %g1, %g2, %g3 ++0x86 0x30 0x40 0x02 ++ ++# CHECK: xor %g1, %g2, %g3 ++0x86 0x18 0x40 0x02 ++ ++# CHECK: xnor %g1, %g2, %g3 ++0x86 0x38 0x40 0x02 ++ ++# CHECK: umul %g1, %g2, %g3 ++0x86 0x50 0x40 0x02 ++ ++# CHECK: smul %g1, %g2, %g3 ++0x86 0x58 0x40 0x02 ++ ++# CHECK: nop ++0x01 0x00 0x00 0x00 ++ ++# CHECK: sethi 10, %l0 ++0x21 0x00 0x00 0x0a ++ ++# CHECK: sll %g1, %g2, %g3 ++0x87 0x28 0x40 0x02 ++ ++# CHECK: sll %g1, 31, %g3 ++0x87 0x28 0x60 0x1f ++ ++# CHECK: srl %g1, %g2, %g3 ++0x87 0x30 0x40 0x02 ++ ++# CHECK: srl %g1, 31, %g3 ++0x87 0x30 0x60 0x1f ++ ++# CHECK: sra %g1, %g2, %g3 ++0x87 0x38 0x40 0x02 ++ ++# CHECK: sra %g1, 31, %g3 ++0x87 0x38 0x60 0x1f ++ ++# CHECK: sub %g1, %g2, %g3 ++0x86 0x20 0x40 0x02 ++ ++# CHECK: subcc %g1, %g2, %g3 ++0x86 0xa0 0x40 0x02 ++ ++# CHECK: subxcc %g1, %g2, %g3 ++0x86 0xe0 0x40 0x02 diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198592-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198592-sparc.diff new file mode 100644 index 0000000..722290e --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198592-sparc.diff @@ -0,0 +1,33 @@ +Pull in r198592 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Explicitly cast -1 to unsigned to fix buildbot errors. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/Disassembler/SparcDisassembler.cpp +=================================================================== +--- lib/Target/Sparc/Disassembler/SparcDisassembler.cpp ++++ lib/Target/Sparc/Disassembler/SparcDisassembler.cpp +@@ -104,14 +104,14 @@ static const unsigned DFPRegDecoderTable[] = { + SP::D14, SP::D30, SP::D15, SP::D31 }; + + static const unsigned QFPRegDecoderTable[] = { +- SP::Q0, SP::Q8, -1, -1, +- SP::Q1, SP::Q9, -1, -1, +- SP::Q2, SP::Q10, -1, -1, +- SP::Q3, SP::Q11, -1, -1, +- SP::Q4, SP::Q12, -1, -1, +- SP::Q5, SP::Q13, -1, -1, +- SP::Q6, SP::Q14, -1, -1, +- SP::Q7, SP::Q15, -1, -1 } ; ++ SP::Q0, SP::Q8, (unsigned)-1, (unsigned)-1, ++ SP::Q1, SP::Q9, (unsigned)-1, (unsigned)-1, ++ SP::Q2, SP::Q10, (unsigned)-1, (unsigned)-1, ++ SP::Q3, SP::Q11, (unsigned)-1, (unsigned)-1, ++ SP::Q4, SP::Q12, (unsigned)-1, (unsigned)-1, ++ SP::Q5, SP::Q13, (unsigned)-1, (unsigned)-1, ++ SP::Q6, SP::Q14, (unsigned)-1, (unsigned)-1, ++ SP::Q7, SP::Q15, (unsigned)-1, (unsigned)-1 } ; + + static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst, + unsigned RegNo, diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198658-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198658-sparc.diff new file mode 100644 index 0000000..b7eb2a2 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198658-sparc.diff @@ -0,0 +1,359 @@ +Pull in r198658 from upstream llvm trunk: + + [Sparc] Add support for parsing memory operands in sparc AsmParser. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/MC/Sparc/sparc-ctrl-instructions.s +=================================================================== +--- test/MC/Sparc/sparc-ctrl-instructions.s ++++ test/MC/Sparc/sparc-ctrl-instructions.s +@@ -0,0 +1,23 @@ ++! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s ++! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s ++ ++ ! CHECK: call foo ++ call foo ++ ++ ! CHECK: call %g1+%i2 ++ call %g1 + %i2 ++ ++ ! CHECK: call %o1+8 ++ call %o1 + 8 ++ ++ ! CHECK: call %g1 ++ call %g1 ++ ++ ! CHECK: jmp %g1+%i2 ++ jmp %g1 + %i2 ++ ++ ! CHECK: jmp %o1+8 ++ jmp %o1 + 8 ++ ++ ! CHECK: jmp %g1 ++ jmp %g1 +Index: test/MC/Sparc/sparc-mem-instructions.s +=================================================================== +--- test/MC/Sparc/sparc-mem-instructions.s ++++ test/MC/Sparc/sparc-mem-instructions.s +@@ -0,0 +1,58 @@ ++! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s ++! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s ++ ++ ! CHECK: ldsb [%i0+%l6], %o2 ! encoding: [0xd4,0x4e,0x00,0x16] ++ ldsb [%i0 + %l6], %o2 ++ ! CHECK: ldsb [%i0+32], %o2 ! encoding: [0xd4,0x4e,0x20,0x20] ++ ldsb [%i0 + 32], %o2 ++ ! CHECK: ldsb [%g1], %o4 ! encoding: [0xd8,0x48,0x60,0x00] ++ ldsb [%g1], %o4 ++ ++ ! CHECK: ldsh [%i0+%l6], %o2 ! encoding: [0xd4,0x56,0x00,0x16] ++ ldsh [%i0 + %l6], %o2 ++ ! CHECK: ldsh [%i0+32], %o2 ! encoding: [0xd4,0x56,0x20,0x20] ++ ldsh [%i0 + 32], %o2 ++ ! CHECK: ldsh [%g1], %o4 ! encoding: [0xd8,0x50,0x60,0x00] ++ ldsh [%g1], %o4 ++ ++ ! CHECK: ldub [%i0+%l6], %o2 ! encoding: [0xd4,0x0e,0x00,0x16] ++ ldub [%i0 + %l6], %o2 ++ ! CHECK: ldub [%i0+32], %o2 ! encoding: [0xd4,0x0e,0x20,0x20] ++ ldub [%i0 + 32], %o2 ++ ! CHECK: ldub [%g1], %o2 ! encoding: [0xd4,0x08,0x60,0x00] ++ ldub [%g1], %o2 ++ ++ ! CHECK: lduh [%i0+%l6], %o2 ! encoding: [0xd4,0x16,0x00,0x16] ++ lduh [%i0 + %l6], %o2 ++ ! CHECK: lduh [%i0+32], %o2 ! encoding: [0xd4,0x16,0x20,0x20] ++ lduh [%i0 + 32], %o2 ++ ! CHECK: lduh [%g1], %o2 ! encoding: [0xd4,0x10,0x60,0x00] ++ lduh [%g1], %o2 ++ ++ ! CHECK: ld [%i0+%l6], %o2 ! encoding: [0xd4,0x06,0x00,0x16] ++ ld [%i0 + %l6], %o2 ++ ! CHECK: ld [%i0+32], %o2 ! encoding: [0xd4,0x06,0x20,0x20] ++ ld [%i0 + 32], %o2 ++ ! CHECK: ld [%g1], %o2 ! encoding: [0xd4,0x00,0x60,0x00] ++ ld [%g1], %o2 ++ ++ ! CHECK: stb %o2, [%i0+%l6] ! encoding: [0xd4,0x2e,0x00,0x16] ++ stb %o2, [%i0 + %l6] ++ ! CHECK: stb %o2, [%i0+32] ! encoding: [0xd4,0x2e,0x20,0x20] ++ stb %o2, [%i0 + 32] ++ ! CHECK: stb %o2, [%g1] ! encoding: [0xd4,0x28,0x60,0x00] ++ stb %o2, [%g1] ++ ++ ! CHECK: sth %o2, [%i0+%l6] ! encoding: [0xd4,0x36,0x00,0x16] ++ sth %o2, [%i0 + %l6] ++ ! CHECK: sth %o2, [%i0+32] ! encoding: [0xd4,0x36,0x20,0x20] ++ sth %o2, [%i0 + 32] ++ ! CHECK: sth %o2, [%g1] ! encoding: [0xd4,0x30,0x60,0x00] ++ sth %o2, [%g1] ++ ++ ! CHECK: st %o2, [%i0+%l6] ! encoding: [0xd4,0x26,0x00,0x16] ++ st %o2, [%i0 + %l6] ++ ! CHECK: st %o2, [%i0+32] ! encoding: [0xd4,0x26,0x20,0x20] ++ st %o2, [%i0 + 32] ++ ! CHECK: st %o2, [%g1] ! encoding: [0xd4,0x20,0x60,0x00] ++ st %o2, [%g1] +Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +=================================================================== +--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp ++++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +@@ -28,6 +28,7 @@ namespace llvm { + } + + namespace { ++class SparcOperand; + class SparcAsmParser : public MCTargetAsmParser { + + MCSubtargetInfo &STI; +@@ -55,18 +56,15 @@ class SparcAsmParser : public MCTargetAsmParser { + + // Custom parse functions for Sparc specific operands. + OperandMatchResultTy +- parseMEMrrOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands); +- OperandMatchResultTy +- parseMEMriOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands); ++ parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands); + + OperandMatchResultTy +- parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, +- int ImmOffsetOrReg); +- +- OperandMatchResultTy + parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, + StringRef Name); + ++ OperandMatchResultTy ++ parseSparcAsmOperand(SparcOperand *&Operand); ++ + // returns true if Tok is matched to a register and returns register in RegNo. + bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo, bool isDFP, + bool isQFP); +@@ -298,7 +296,35 @@ class SparcOperand : public MCParsedAsmOperand { + return Op; + } + ++ static SparcOperand *MorphToMEMrr(unsigned Base, SparcOperand *Op) { ++ unsigned offsetReg = Op->getReg(); ++ Op->Kind = k_MemoryReg; ++ Op->Mem.Base = Base; ++ Op->Mem.OffsetReg = offsetReg; ++ Op->Mem.Off = 0; ++ return Op; ++ } + ++ static SparcOperand *CreateMEMri(unsigned Base, ++ const MCExpr *Off, ++ SMLoc S, SMLoc E) { ++ SparcOperand *Op = new SparcOperand(k_MemoryImm); ++ Op->Mem.Base = Base; ++ Op->Mem.OffsetReg = 0; ++ Op->Mem.Off = Off; ++ Op->StartLoc = S; ++ Op->EndLoc = E; ++ return Op; ++ } ++ ++ static SparcOperand *MorphToMEMri(unsigned Base, SparcOperand *Op) { ++ const MCExpr *Imm = Op->getImm(); ++ Op->Kind = k_MemoryImm; ++ Op->Mem.Base = Base; ++ Op->Mem.OffsetReg = 0; ++ Op->Mem.Off = Imm; ++ return Op; ++ } + }; + + } // end namespace +@@ -412,23 +438,42 @@ ParseDirective(AsmToken DirectiveID) + } + + SparcAsmParser::OperandMatchResultTy SparcAsmParser:: +-parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, +- int ImmOffsetOrReg) ++parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) + { +- // FIXME: Implement memory operand parsing here. +- return MatchOperand_NoMatch; +-} + +-SparcAsmParser::OperandMatchResultTy SparcAsmParser:: +-parseMEMrrOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) +-{ +- return parseMEMOperand(Operands, 2); +-} ++ SMLoc S, E; ++ unsigned BaseReg = 0; + +-SparcAsmParser::OperandMatchResultTy SparcAsmParser:: +-parseMEMriOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands) +-{ +- return parseMEMOperand(Operands, 1); ++ if (ParseRegister(BaseReg, S, E)) { ++ return MatchOperand_NoMatch; ++ } ++ ++ switch (getLexer().getKind()) { ++ default: return MatchOperand_NoMatch; ++ ++ case AsmToken::RBrac: ++ case AsmToken::EndOfStatement: ++ Operands.push_back(SparcOperand::CreateMEMri(BaseReg, 0, S, E)); ++ return MatchOperand_Success; ++ ++ case AsmToken:: Plus: ++ Parser.Lex(); // Eat the '+' ++ break; ++ case AsmToken::Minus: ++ break; ++ } ++ ++ SparcOperand *Offset = 0; ++ OperandMatchResultTy ResTy = parseSparcAsmOperand(Offset); ++ if (ResTy != MatchOperand_Success || !Offset) ++ return MatchOperand_NoMatch; ++ ++ Offset = (Offset->isImm() ++ ? SparcOperand::MorphToMEMri(BaseReg, Offset) ++ : SparcOperand::MorphToMEMrr(BaseReg, Offset)); ++ ++ Operands.push_back(Offset); ++ return MatchOperand_Success; + } + + SparcAsmParser::OperandMatchResultTy SparcAsmParser:: +@@ -435,20 +480,57 @@ SparcAsmParser::OperandMatchResultTy SparcAsmParse + parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands, + StringRef Mnemonic) + { ++ + OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic); +- if (ResTy == MatchOperand_Success) +- return ResTy; ++ + // If there wasn't a custom match, try the generic matcher below. Otherwise, + // there was a match, but an error occurred, in which case, just return that + // the operand parsing failed. +- if (ResTy == MatchOperand_ParseFail) ++ if (ResTy == MatchOperand_Success || ResTy == MatchOperand_ParseFail) + return ResTy; + ++ if (getLexer().is(AsmToken::LBrac)) { ++ // Memory operand ++ Operands.push_back(SparcOperand::CreateToken("[", ++ Parser.getTok().getLoc())); ++ Parser.Lex(); // Eat the [ ++ ++ ResTy = parseMEMOperand(Operands); ++ if (ResTy != MatchOperand_Success) ++ return ResTy; ++ ++ if (!getLexer().is(AsmToken::RBrac)) ++ return MatchOperand_ParseFail; ++ ++ Operands.push_back(SparcOperand::CreateToken("]", ++ Parser.getTok().getLoc())); ++ Parser.Lex(); // Eat the ] ++ return MatchOperand_Success; ++ } ++ ++ SparcOperand *Op = 0; ++ ResTy = parseSparcAsmOperand(Op); ++ if (ResTy != MatchOperand_Success || !Op) ++ return MatchOperand_ParseFail; ++ ++ // Push the parsed operand into the list of operands ++ Operands.push_back(Op); ++ ++ return MatchOperand_Success; ++} ++ ++SparcAsmParser::OperandMatchResultTy ++SparcAsmParser::parseSparcAsmOperand(SparcOperand *&Op) ++{ ++ + SMLoc S = Parser.getTok().getLoc(); + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + const MCExpr *EVal; +- SparcOperand *Op; ++ ++ Op = 0; + switch (getLexer().getKind()) { ++ default: break; ++ + case AsmToken::Percent: + Parser.Lex(); // Eat the '%'. + unsigned RegNo; +@@ -458,40 +540,30 @@ parseOperand(SmallVectorImpl<MCParsedAsmOperand*> + break; + } + // FIXME: Handle modifiers like %hi, %lo etc., +- return MatchOperand_ParseFail; ++ break; + + case AsmToken::Minus: + case AsmToken::Integer: +- if (getParser().parseExpression(EVal)) +- return MatchOperand_ParseFail; +- +- Op = SparcOperand::CreateImm(EVal, S, E); ++ if (!getParser().parseExpression(EVal)) ++ Op = SparcOperand::CreateImm(EVal, S, E); + break; + + case AsmToken::Identifier: { + StringRef Identifier; +- if (getParser().parseIdentifier(Identifier)) +- return MatchOperand_ParseFail; +- SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); +- MCSymbol *Sym = getContext().GetOrCreateSymbol(Identifier); ++ if (!getParser().parseIdentifier(Identifier)) { ++ SMLoc E = SMLoc::getFromPointer(Parser.getTok(). ++ getLoc().getPointer() - 1); ++ MCSymbol *Sym = getContext().GetOrCreateSymbol(Identifier); + +- // Otherwise create a symbol reference. +- const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, +- getContext()); ++ const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, ++ getContext()); + +- Op = SparcOperand::CreateImm(Res, S, E); ++ Op = SparcOperand::CreateImm(Res, S, E); ++ } + break; + } +- +- case AsmToken::LBrac: // handle [ +- return parseMEMOperand(Operands, 0); +- +- default: +- return MatchOperand_ParseFail; + } +- // Push the parsed operand into the list of operands +- Operands.push_back(Op); +- return MatchOperand_Success; ++ return (Op) ? MatchOperand_Success : MatchOperand_ParseFail; + } + + bool SparcAsmParser::matchRegisterName(const AsmToken &Tok, +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -78,12 +78,12 @@ def ADDRri : ComplexPattern<iPTR, 2, "SelectADDRri + // Address operands + def SparcMEMrrAsmOperand : AsmOperandClass { + let Name = "MEMrr"; +- let ParserMethod = "parseMEMrrOperand"; ++ let ParserMethod = "parseMEMOperand"; + } + + def SparcMEMriAsmOperand : AsmOperandClass { + let Name = "MEMri"; +- let ParserMethod = "parseMEMriOperand"; ++ let ParserMethod = "parseMEMOperand"; + } + + def MEMrr : Operand<iPTR> { diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198681-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198681-sparc.diff new file mode 100644 index 0000000..4bd12d2 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198681-sparc.diff @@ -0,0 +1,298 @@ +Pull in r198681 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add support for parsing sparc asm modifiers such as %hi, %lo etc., + Also, correct the offsets for FixupsKindInfo. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +@@ -27,11 +27,11 @@ static unsigned adjustFixupValue(unsigned Kind, ui + case FK_Data_8: + return Value; + case Sparc::fixup_sparc_call30: +- return Value & 0x3fffffff; ++ return (Value >> 2) & 0x3fffffff; + case Sparc::fixup_sparc_br22: +- return Value & 0x3fffff; ++ return (Value >> 2) & 0x3fffff; + case Sparc::fixup_sparc_br19: +- return Value & 0x1ffff; ++ return (Value >> 2) & 0x1ffff; + case Sparc::fixup_sparc_hi22: + return (Value >> 10) & 0x3fffff; + case Sparc::fixup_sparc_lo10: +@@ -45,7 +45,7 @@ static unsigned adjustFixupValue(unsigned Kind, ui + case Sparc::fixup_sparc_hh: + return (Value >> 42) & 0x3fffff; + case Sparc::fixup_sparc_hm: +- return (Value >>32) & 0x3ff; ++ return (Value >> 32) & 0x3ff; + } + } + +@@ -62,16 +62,16 @@ namespace { + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const { + const static MCFixupKindInfo Infos[Sparc::NumTargetFixupKinds] = { + // name offset bits flags +- { "fixup_sparc_call30", 0, 30, MCFixupKindInfo::FKF_IsPCRel }, +- { "fixup_sparc_br22", 0, 22, MCFixupKindInfo::FKF_IsPCRel }, +- { "fixup_sparc_br19", 0, 19, MCFixupKindInfo::FKF_IsPCRel }, +- { "fixup_sparc_hi22", 0, 22, 0 }, +- { "fixup_sparc_lo10", 0, 10, 0 }, +- { "fixup_sparc_h44", 0, 22, 0 }, +- { "fixup_sparc_m44", 0, 10, 0 }, +- { "fixup_sparc_l44", 0, 12, 0 }, +- { "fixup_sparc_hh", 0, 21, 0 }, +- { "fixup_sparc_hm", 0, 10, 0 }, ++ { "fixup_sparc_call30", 2, 30, MCFixupKindInfo::FKF_IsPCRel }, ++ { "fixup_sparc_br22", 10, 22, MCFixupKindInfo::FKF_IsPCRel }, ++ { "fixup_sparc_br19", 13, 19, MCFixupKindInfo::FKF_IsPCRel }, ++ { "fixup_sparc_hi22", 10, 22, 0 }, ++ { "fixup_sparc_lo10", 22, 10, 0 }, ++ { "fixup_sparc_h44", 10, 22, 0 }, ++ { "fixup_sparc_m44", 22, 10, 0 }, ++ { "fixup_sparc_l44", 20, 12, 0 }, ++ { "fixup_sparc_hh", 10, 22, 0 }, ++ { "fixup_sparc_hm", 22, 10, 0 }, + }; + + if (Kind < FirstTargetFixupKind) +Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +@@ -67,6 +67,37 @@ void SparcMCExpr::PrintImpl(raw_ostream &OS) const + OS << ')'; + } + ++SparcMCExpr::VariantKind SparcMCExpr::parseVariantKind(StringRef name) ++{ ++ return StringSwitch<SparcMCExpr::VariantKind>(name) ++ .Case("lo", VK_Sparc_LO) ++ .Case("hi", VK_Sparc_HI) ++ .Case("h44", VK_Sparc_H44) ++ .Case("m44", VK_Sparc_M44) ++ .Case("l44", VK_Sparc_L44) ++ .Case("hh", VK_Sparc_HH) ++ .Case("hm", VK_Sparc_HM) ++ .Case("tgd_hi22", VK_Sparc_TLS_GD_HI22) ++ .Case("tgd_lo10", VK_Sparc_TLS_GD_LO10) ++ .Case("tgd_add", VK_Sparc_TLS_GD_ADD) ++ .Case("tgd_call", VK_Sparc_TLS_GD_CALL) ++ .Case("tldm_hi22", VK_Sparc_TLS_LDM_HI22) ++ .Case("tldm_lo10", VK_Sparc_TLS_LDM_LO10) ++ .Case("tldm_add", VK_Sparc_TLS_LDM_ADD) ++ .Case("tldm_call", VK_Sparc_TLS_LDM_CALL) ++ .Case("tldo_hix22", VK_Sparc_TLS_LDO_HIX22) ++ .Case("tldo_lox10", VK_Sparc_TLS_LDO_LOX10) ++ .Case("tldo_add", VK_Sparc_TLS_LDO_ADD) ++ .Case("tie_hi22", VK_Sparc_TLS_IE_HI22) ++ .Case("tie_lo10", VK_Sparc_TLS_IE_LO10) ++ .Case("tie_ld", VK_Sparc_TLS_IE_LD) ++ .Case("tie_ldx", VK_Sparc_TLS_IE_LDX) ++ .Case("tie_add", VK_Sparc_TLS_IE_ADD) ++ .Case("tle_hix22", VK_Sparc_TLS_LE_HIX22) ++ .Case("tle_lox10", VK_Sparc_TLS_LE_LOX10) ++ .Default(VK_Sparc_None); ++} ++ + bool + SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const { +Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h ++++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h +@@ -19,6 +19,7 @@ + + namespace llvm { + ++class StringRef; + class SparcMCExpr : public MCTargetExpr { + public: + enum VariantKind { +@@ -90,6 +91,7 @@ class SparcMCExpr : public MCTargetExpr { + + static bool classof(const SparcMCExpr *) { return true; } + ++ static VariantKind parseVariantKind(StringRef name); + + }; + +Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +=================================================================== +--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp ++++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +@@ -8,6 +8,7 @@ + //===----------------------------------------------------------------------===// + + #include "MCTargetDesc/SparcMCTargetDesc.h" ++#include "MCTargetDesc/SparcMCExpr.h" + #include "llvm/ADT/STLExtras.h" + #include "llvm/MC/MCContext.h" + #include "llvm/MC/MCInst.h" +@@ -68,6 +69,7 @@ class SparcAsmParser : public MCTargetAsmParser { + // returns true if Tok is matched to a register and returns register in RegNo. + bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo, bool isDFP, + bool isQFP); ++ bool matchSparcAsmModifiers(const MCExpr *&EVal, SMLoc &EndLoc); + + public: + SparcAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser, +@@ -536,15 +538,19 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand + unsigned RegNo; + if (matchRegisterName(Parser.getTok(), RegNo, false, false)) { + Parser.Lex(); // Eat the identifier token. ++ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Op = SparcOperand::CreateReg(RegNo, SparcOperand::rk_None, S, E); + break; + } +- // FIXME: Handle modifiers like %hi, %lo etc., ++ if (matchSparcAsmModifiers(EVal, E)) { ++ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); ++ Op = SparcOperand::CreateImm(EVal, S, E); ++ } + break; + + case AsmToken::Minus: + case AsmToken::Integer: +- if (!getParser().parseExpression(EVal)) ++ if (!getParser().parseExpression(EVal, E)) + Op = SparcOperand::CreateImm(EVal, S, E); + break; + +@@ -551,13 +557,11 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand + case AsmToken::Identifier: { + StringRef Identifier; + if (!getParser().parseIdentifier(Identifier)) { +- SMLoc E = SMLoc::getFromPointer(Parser.getTok(). +- getLoc().getPointer() - 1); ++ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + MCSymbol *Sym = getContext().GetOrCreateSymbol(Identifier); + + const MCExpr *Res = MCSymbolRefExpr::Create(Sym, MCSymbolRefExpr::VK_None, + getContext()); +- + Op = SparcOperand::CreateImm(Res, S, E); + } + break; +@@ -675,7 +679,33 @@ bool SparcAsmParser::matchRegisterName(const AsmTo + } + + ++bool SparcAsmParser::matchSparcAsmModifiers(const MCExpr *&EVal, ++ SMLoc &EndLoc) ++{ ++ AsmToken Tok = Parser.getTok(); ++ if (!Tok.is(AsmToken::Identifier)) ++ return false; + ++ StringRef name = Tok.getString(); ++ ++ SparcMCExpr::VariantKind VK = SparcMCExpr::parseVariantKind(name); ++ ++ if (VK == SparcMCExpr::VK_Sparc_None) ++ return false; ++ ++ Parser.Lex(); // Eat the identifier. ++ if (Parser.getTok().getKind() != AsmToken::LParen) ++ return false; ++ ++ Parser.Lex(); // Eat the LParen token. ++ const MCExpr *subExpr; ++ if (Parser.parseParenExpression(subExpr, EndLoc)) ++ return false; ++ EVal = SparcMCExpr::Create(VK, subExpr, getContext()); ++ return true; ++} ++ ++ + extern "C" void LLVMInitializeSparcAsmParser() { + RegisterMCAsmParser<SparcAsmParser> A(TheSparcTarget); + RegisterMCAsmParser<SparcAsmParser> B(TheSparcV9Target); +Index: test/MC/Sparc/sparc-relocations.s +=================================================================== +--- test/MC/Sparc/sparc-relocations.s ++++ test/MC/Sparc/sparc-relocations.s +@@ -0,0 +1,33 @@ ++! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s ++ ++ ! CHECK: call foo ! encoding: [0b01AAAAAA,A,A,A] ++ ! CHECK: ! fixup A - offset: 0, value: foo, kind: fixup_sparc_call30 ++ call foo ++ ++ ! CHECK: or %g1, %lo(sym), %g3 ! encoding: [0x86,0x10,0b011000AA,A] ++ ! CHECK-NEXT ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10 ++ or %g1, %lo(sym), %g3 ++ ++ ! CHECK: sethi %hi(sym), %l0 ! encoding: [0x21,0b00AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: %hi(sym), kind: fixup_sparc_hi22 ++ sethi %hi(sym), %l0 ++ ++ ! CHECK: sethi %h44(sym), %l0 ! encoding: [0x21,0b00AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: %h44(sym), kind: fixup_sparc_h44 ++ sethi %h44(sym), %l0 ++ ++ ! CHECK: or %g1, %m44(sym), %g3 ! encoding: [0x86,0x10,0b011000AA,A] ++ ! CHECK-NEXT ! fixup A - offset: 0, value: %m44(sym), kind: fixup_sparc_m44 ++ or %g1, %m44(sym), %g3 ++ ++ ! CHECK: or %g1, %l44(sym), %g3 ! encoding: [0x86,0x10,0b0110AAAA,A] ++ ! CHECK-NEXT ! fixup A - offset: 0, value: %l44(sym), kind: fixup_sparc_l44 ++ or %g1, %l44(sym), %g3 ++ ++ ! CHECK: sethi %hh(sym), %l0 ! encoding: [0x21,0b00AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: %hh(sym), kind: fixup_sparc_hh ++ sethi %hh(sym), %l0 ++ ++ ! CHECK: or %g1, %hm(sym), %g3 ! encoding: [0x86,0x10,0b011000AA,A] ++ ! CHECK-NEXT ! fixup A - offset: 0, value: %hm(sym), kind: fixup_sparc_hm ++ or %g1, %hm(sym), %g3 +Index: test/MC/Sparc/sparc-ctrl-instructions.s +=================================================================== +--- test/MC/Sparc/sparc-ctrl-instructions.s ++++ test/MC/Sparc/sparc-ctrl-instructions.s +@@ -1,23 +1,33 @@ + ! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s + ! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s + +- ! CHECK: call foo ++ ! CHECK: call foo ! encoding: [0b01AAAAAA,A,A,A] ++ ! CHECK: ! fixup A - offset: 0, value: foo, kind: fixup_sparc_call30 + call foo + +- ! CHECK: call %g1+%i2 ++ ! CHECK: call %g1+%i2 ! encoding: [0x9f,0xc0,0x40,0x1a] + call %g1 + %i2 + +- ! CHECK: call %o1+8 ++ ! CHECK: call %o1+8 ! encoding: [0x9f,0xc2,0x60,0x08] + call %o1 + 8 + +- ! CHECK: call %g1 ++ ! CHECK: call %g1 ! encoding: [0x9f,0xc0,0x60,0x00] + call %g1 + +- ! CHECK: jmp %g1+%i2 ++ ! CHECK: call %g1+%lo(sym) ! encoding: [0x9f,0xc0,0b011000AA,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10 ++ call %g1+%lo(sym) ++ ++ ! CHECK: jmp %g1+%i2 ! encoding: [0x81,0xc0,0x40,0x1a] + jmp %g1 + %i2 + +- ! CHECK: jmp %o1+8 ++ ! CHECK: jmp %o1+8 ! encoding: [0x81,0xc2,0x60,0x08] + jmp %o1 + 8 + +- ! CHECK: jmp %g1 ++ ! CHECK: jmp %g1 ! encoding: [0x81,0xc0,0x60,0x00] + jmp %g1 ++ ++ ! CHECK: jmp %g1+%lo(sym) ! encoding: [0x81,0xc0,0b011000AA,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10 ++ jmp %g1+%lo(sym) ++ diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198738-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198738-sparc.diff new file mode 100644 index 0000000..87637a7 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198738-sparc.diff @@ -0,0 +1,734 @@ +Pull in r198738 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add support for parsing branch instructions and conditional moves. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/MC/Disassembler/Sparc/sparc.txt +=================================================================== +--- test/MC/Disassembler/Sparc/sparc.txt ++++ test/MC/Disassembler/Sparc/sparc.txt +@@ -80,3 +80,90 @@ + + # CHECK: subxcc %g1, %g2, %g3 + 0x86 0xe0 0x40 0x02 ++ ++# CHECK: ba 4194303 ++0x10 0xbf 0xff 0xff ++ ++# CHECK: bne 4194303 ++0x12 0xbf 0xff 0xff ++ ++# CHECK: be 4194303 ++0x02 0xbf 0xff 0xff ++ ++# CHECK: bg 4194303 ++0x14 0xbf 0xff 0xff ++ ++# CHECK: ble 4194303 ++0x04 0xbf 0xff 0xff ++ ++# CHECK: bge 4194303 ++0x16 0xbf 0xff 0xff ++ ++# CHECK: bl 4194303 ++0x06 0xbf 0xff 0xff ++ ++# CHECK: bgu 4194303 ++0x18 0xbf 0xff 0xff ++ ++# CHECK: bleu 4194303 ++0x08 0xbf 0xff 0xff ++ ++# CHECK: bcc 4194303 ++0x1a 0xbf 0xff 0xff ++ ++# CHECK: bcs 4194303 ++0x0a 0xbf 0xff 0xff ++ ++# CHECK: bpos 4194303 ++0x1c 0xbf 0xff 0xff ++ ++# CHECK: bneg 4194303 ++0x0c 0xbf 0xff 0xff ++ ++# CHECK: bvc 4194303 ++0x1e 0xbf 0xff 0xff ++ ++# CHECK: bvs 4194303 ++0x0e 0xbf 0xff 0xff ++ ++# CHECK: fbu 4194303 ++0x0f 0xbf 0xff 0xff ++ ++# CHECK: fbg 4194303 ++0x0d 0xbf 0xff 0xff ++ ++# CHECK: fbug 4194303 ++0x0b 0xbf 0xff 0xff ++ ++# CHECK: fbl 4194303 ++0x09 0xbf 0xff 0xff ++ ++# CHECK: fbul 4194303 ++0x07 0xbf 0xff 0xff ++ ++# CHECK: fblg 4194303 ++0x05 0xbf 0xff 0xff ++ ++# CHECK: fbne 4194303 ++0x03 0xbf 0xff 0xff ++ ++# CHECK: fbe 4194303 ++0x13 0xbf 0xff 0xff ++ ++# CHECK: fbue 4194303 ++0x15 0xbf 0xff 0xff ++ ++# CHECK: fbge 4194303 ++0x17 0xbf 0xff 0xff ++ ++# CHECK: fbuge 4194303 ++0x19 0xbf 0xff 0xff ++ ++# CHECK: fble 4194303 ++0x1b 0xbf 0xff 0xff ++ ++# CHECK: fbule 4194303 ++0x1d 0xbf 0xff 0xff ++ ++# CHECK: fbo 4194303 ++0x1f 0xbf 0xff 0xff +Index: test/MC/Sparc/sparc-ctrl-instructions.s +=================================================================== +--- test/MC/Sparc/sparc-ctrl-instructions.s ++++ test/MC/Sparc/sparc-ctrl-instructions.s +@@ -31,3 +31,117 @@ + ! CHECK-NEXT: ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10 + jmp %g1+%lo(sym) + ++ ! CHECK: ba .BB0 ! encoding: [0x10,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ ba .BB0 ++ ++ ! CHECK: bne .BB0 ! encoding: [0x12,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ bne .BB0 ++ ++ ! CHECK: be .BB0 ! encoding: [0x02,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ be .BB0 ++ ++ ! CHECK: bg .BB0 ! encoding: [0x14,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ bg .BB0 ++ ++ ! CHECK: ble .BB0 ! encoding: [0x04,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ ble .BB0 ++ ++ ! CHECK: bge .BB0 ! encoding: [0x16,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ bge .BB0 ++ ++ ! CHECK: bl .BB0 ! encoding: [0x06,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ bl .BB0 ++ ++ ! CHECK: bgu .BB0 ! encoding: [0x18,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ bgu .BB0 ++ ++ ! CHECK: bleu .BB0 ! encoding: [0x08,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ bleu .BB0 ++ ++ ! CHECK: bcc .BB0 ! encoding: [0x1a,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ bcc .BB0 ++ ++ ! CHECK: bcs .BB0 ! encoding: [0x0a,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ bcs .BB0 ++ ++ ! CHECK: bpos .BB0 ! encoding: [0x1c,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ bpos .BB0 ++ ++ ! CHECK: bneg .BB0 ! encoding: [0x0c,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ bneg .BB0 ++ ++ ! CHECK: bvc .BB0 ! encoding: [0x1e,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ bvc .BB0 ++ ++ ! CHECK: bvs .BB0 ! encoding: [0x0e,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ bvs .BB0 ++ ++ ! CHECK: fbu .BB0 ! encoding: [0x0f,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fbu .BB0 ++ ++ ! CHECK: fbg .BB0 ! encoding: [0x0d,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fbg .BB0 ++ ! CHECK: fbug .BB0 ! encoding: [0x0b,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fbug .BB0 ++ ++ ! CHECK: fbl .BB0 ! encoding: [0x09,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fbl .BB0 ++ ++ ! CHECK: fbul .BB0 ! encoding: [0x07,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fbul .BB0 ++ ++ ! CHECK: fblg .BB0 ! encoding: [0x05,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fblg .BB0 ++ ++ ! CHECK: fbne .BB0 ! encoding: [0x03,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fbne .BB0 ++ ++ ! CHECK: fbe .BB0 ! encoding: [0x13,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fbe .BB0 ++ ++ ! CHECK: fbue .BB0 ! encoding: [0x15,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fbue .BB0 ++ ++ ! CHECK: fbge .BB0 ! encoding: [0x17,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fbge .BB0 ++ ++ ! CHECK: fbuge .BB0 ! encoding: [0x19,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fbuge .BB0 ++ ++ ! CHECK: fble .BB0 ! encoding: [0x1b,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fble .BB0 ++ ++ ! CHECK: fbule .BB0 ! encoding: [0x1d,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fbule .BB0 ++ ++ ! CHECK: fbo .BB0 ! encoding: [0x1f,0b10AAAAAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 ++ fbo .BB0 +Index: test/MC/Sparc/sparc64-ctrl-instructions.s +=================================================================== +--- test/MC/Sparc/sparc64-ctrl-instructions.s ++++ test/MC/Sparc/sparc64-ctrl-instructions.s +@@ -0,0 +1,235 @@ ++! RUN: llvm-mc %s -triple=sparc64-unknown-linux-gnu -show-encoding | FileCheck %s ++ ++ ++ ! CHECK: bne %xcc, .BB0 ! encoding: [0x12,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ bne %xcc, .BB0 ++ ++ ! CHECK: be %xcc, .BB0 ! encoding: [0x02,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ be %xcc, .BB0 ++ ++ ! CHECK: bg %xcc, .BB0 ! encoding: [0x14,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ bg %xcc, .BB0 ++ ++ ! CHECK: ble %xcc, .BB0 ! encoding: [0x04,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ ble %xcc, .BB0 ++ ++ ! CHECK: bge %xcc, .BB0 ! encoding: [0x16,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ bge %xcc, .BB0 ++ ++ ! CHECK: bl %xcc, .BB0 ! encoding: [0x06,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ bl %xcc, .BB0 ++ ++ ! CHECK: bgu %xcc, .BB0 ! encoding: [0x18,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ bgu %xcc, .BB0 ++ ++ ! CHECK: bleu %xcc, .BB0 ! encoding: [0x08,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ bleu %xcc, .BB0 ++ ++ ! CHECK: bcc %xcc, .BB0 ! encoding: [0x1a,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ bcc %xcc, .BB0 ++ ++ ! CHECK: bcs %xcc, .BB0 ! encoding: [0x0a,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ bcs %xcc, .BB0 ++ ++ ! CHECK: bpos %xcc, .BB0 ! encoding: [0x1c,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ bpos %xcc, .BB0 ++ ++ ! CHECK: bneg %xcc, .BB0 ! encoding: [0x0c,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ bneg %xcc, .BB0 ++ ++ ! CHECK: bvc %xcc, .BB0 ! encoding: [0x1e,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ bvc %xcc, .BB0 ++ ++ ! CHECK: bvs %xcc, .BB0 ! encoding: [0x0e,0b01101AAA,A,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br19 ++ bvs %xcc, .BB0 ++ ++ ++ ! CHECK: movne %icc, %g1, %g2 ! encoding: [0x85,0x66,0x40,0x01] ++ ! CHECK: move %icc, %g1, %g2 ! encoding: [0x85,0x64,0x40,0x01] ++ ! CHECK: movg %icc, %g1, %g2 ! encoding: [0x85,0x66,0x80,0x01] ++ ! CHECK: movle %icc, %g1, %g2 ! encoding: [0x85,0x64,0x80,0x01] ++ ! CHECK: movge %icc, %g1, %g2 ! encoding: [0x85,0x66,0xc0,0x01] ++ ! CHECK: movl %icc, %g1, %g2 ! encoding: [0x85,0x64,0xc0,0x01] ++ ! CHECK: movgu %icc, %g1, %g2 ! encoding: [0x85,0x67,0x00,0x01] ++ ! CHECK: movleu %icc, %g1, %g2 ! encoding: [0x85,0x65,0x00,0x01] ++ ! CHECK: movcc %icc, %g1, %g2 ! encoding: [0x85,0x67,0x40,0x01] ++ ! CHECK: movcs %icc, %g1, %g2 ! encoding: [0x85,0x65,0x40,0x01] ++ ! CHECK: movpos %icc, %g1, %g2 ! encoding: [0x85,0x67,0x80,0x01] ++ ! CHECK: movneg %icc, %g1, %g2 ! encoding: [0x85,0x65,0x80,0x01] ++ ! CHECK: movvc %icc, %g1, %g2 ! encoding: [0x85,0x67,0xc0,0x01] ++ ! CHECK: movvs %icc, %g1, %g2 ! encoding: [0x85,0x65,0xc0,0x01] ++ movne %icc, %g1, %g2 ++ move %icc, %g1, %g2 ++ movg %icc, %g1, %g2 ++ movle %icc, %g1, %g2 ++ movge %icc, %g1, %g2 ++ movl %icc, %g1, %g2 ++ movgu %icc, %g1, %g2 ++ movleu %icc, %g1, %g2 ++ movcc %icc, %g1, %g2 ++ movcs %icc, %g1, %g2 ++ movpos %icc, %g1, %g2 ++ movneg %icc, %g1, %g2 ++ movvc %icc, %g1, %g2 ++ movvs %icc, %g1, %g2 ++ ++ ! CHECK: movne %xcc, %g1, %g2 ! encoding: [0x85,0x66,0x50,0x01] ++ ! CHECK: move %xcc, %g1, %g2 ! encoding: [0x85,0x64,0x50,0x01] ++ ! CHECK: movg %xcc, %g1, %g2 ! encoding: [0x85,0x66,0x90,0x01] ++ ! CHECK: movle %xcc, %g1, %g2 ! encoding: [0x85,0x64,0x90,0x01] ++ ! CHECK: movge %xcc, %g1, %g2 ! encoding: [0x85,0x66,0xd0,0x01] ++ ! CHECK: movl %xcc, %g1, %g2 ! encoding: [0x85,0x64,0xd0,0x01] ++ ! CHECK: movgu %xcc, %g1, %g2 ! encoding: [0x85,0x67,0x10,0x01] ++ ! CHECK: movleu %xcc, %g1, %g2 ! encoding: [0x85,0x65,0x10,0x01] ++ ! CHECK: movcc %xcc, %g1, %g2 ! encoding: [0x85,0x67,0x50,0x01] ++ ! CHECK: movcs %xcc, %g1, %g2 ! encoding: [0x85,0x65,0x50,0x01] ++ ! CHECK: movpos %xcc, %g1, %g2 ! encoding: [0x85,0x67,0x90,0x01] ++ ! CHECK: movneg %xcc, %g1, %g2 ! encoding: [0x85,0x65,0x90,0x01] ++ ! CHECK: movvc %xcc, %g1, %g2 ! encoding: [0x85,0x67,0xd0,0x01] ++ ! CHECK: movvs %xcc, %g1, %g2 ! encoding: [0x85,0x65,0xd0,0x01] ++ movne %xcc, %g1, %g2 ++ move %xcc, %g1, %g2 ++ movg %xcc, %g1, %g2 ++ movle %xcc, %g1, %g2 ++ movge %xcc, %g1, %g2 ++ movl %xcc, %g1, %g2 ++ movgu %xcc, %g1, %g2 ++ movleu %xcc, %g1, %g2 ++ movcc %xcc, %g1, %g2 ++ movcs %xcc, %g1, %g2 ++ movpos %xcc, %g1, %g2 ++ movneg %xcc, %g1, %g2 ++ movvc %xcc, %g1, %g2 ++ movvs %xcc, %g1, %g2 ++ ++ ! CHECK: movu %fcc0, %g1, %g2 ! encoding: [0x85,0x61,0xc0,0x01] ++ ! CHECK: movg %fcc0, %g1, %g2 ! encoding: [0x85,0x61,0x80,0x01] ++ ! CHECK: movug %fcc0, %g1, %g2 ! encoding: [0x85,0x61,0x40,0x01] ++ ! CHECK: movl %fcc0, %g1, %g2 ! encoding: [0x85,0x61,0x00,0x01] ++ ! CHECK: movul %fcc0, %g1, %g2 ! encoding: [0x85,0x60,0xc0,0x01] ++ ! CHECK: movlg %fcc0, %g1, %g2 ! encoding: [0x85,0x60,0x80,0x01] ++ ! CHECK: movne %fcc0, %g1, %g2 ! encoding: [0x85,0x60,0x40,0x01] ++ ! CHECK: move %fcc0, %g1, %g2 ! encoding: [0x85,0x62,0x40,0x01] ++ ! CHECK: movue %fcc0, %g1, %g2 ! encoding: [0x85,0x62,0x80,0x01] ++ ! CHECK: movge %fcc0, %g1, %g2 ! encoding: [0x85,0x62,0xc0,0x01] ++ ! CHECK: movuge %fcc0, %g1, %g2 ! encoding: [0x85,0x63,0x00,0x01] ++ ! CHECK: movle %fcc0, %g1, %g2 ! encoding: [0x85,0x63,0x40,0x01] ++ ! CHECK: movule %fcc0, %g1, %g2 ! encoding: [0x85,0x63,0x80,0x01] ++ ! CHECK: movo %fcc0, %g1, %g2 ! encoding: [0x85,0x63,0xc0,0x01] ++ movu %fcc0, %g1, %g2 ++ movg %fcc0, %g1, %g2 ++ movug %fcc0, %g1, %g2 ++ movl %fcc0, %g1, %g2 ++ movul %fcc0, %g1, %g2 ++ movlg %fcc0, %g1, %g2 ++ movne %fcc0, %g1, %g2 ++ move %fcc0, %g1, %g2 ++ movue %fcc0, %g1, %g2 ++ movge %fcc0, %g1, %g2 ++ movuge %fcc0, %g1, %g2 ++ movle %fcc0, %g1, %g2 ++ movule %fcc0, %g1, %g2 ++ movo %fcc0, %g1, %g2 ++ ++ ++ ! CHECK fmovsne %icc, %f1, %f2 ! encoding: [0x85,0xaa,0x60,0x21] ++ ! CHECK fmovse %icc, %f1, %f2 ! encoding: [0x85,0xa8,0x60,0x21] ++ ! CHECK fmovsg %icc, %f1, %f2 ! encoding: [0x85,0xaa,0xa0,0x21] ++ ! CHECK fmovsle %icc, %f1, %f2 ! encoding: [0x85,0xa8,0xa0,0x21] ++ ! CHECK fmovsge %icc, %f1, %f2 ! encoding: [0x85,0xaa,0xe0,0x21] ++ ! CHECK fmovsl %icc, %f1, %f2 ! encoding: [0x85,0xa8,0xe0,0x21] ++ ! CHECK fmovsgu %icc, %f1, %f2 ! encoding: [0x85,0xab,0x20,0x21] ++ ! CHECK fmovsleu %icc, %f1, %f2 ! encoding: [0x85,0xa9,0x20,0x21] ++ ! CHECK fmovscc %icc, %f1, %f2 ! encoding: [0x85,0xab,0x60,0x21] ++ ! CHECK fmovscs %icc, %f1, %f2 ! encoding: [0x85,0xa9,0x60,0x21] ++ ! CHECK fmovspos %icc, %f1, %f2 ! encoding: [0x85,0xab,0xa0,0x21] ++ ! CHECK fmovsneg %icc, %f1, %f2 ! encoding: [0x85,0xa9,0xa0,0x21] ++ ! CHECK fmovsvc %icc, %f1, %f2 ! encoding: [0x85,0xab,0xe0,0x21] ++ ! CHECK fmovsvs %icc, %f1, %f2 ! encoding: [0x85,0xa9,0xe0,0x21] ++ fmovsne %icc, %f1, %f2 ++ fmovse %icc, %f1, %f2 ++ fmovsg %icc, %f1, %f2 ++ fmovsle %icc, %f1, %f2 ++ fmovsge %icc, %f1, %f2 ++ fmovsl %icc, %f1, %f2 ++ fmovsgu %icc, %f1, %f2 ++ fmovsleu %icc, %f1, %f2 ++ fmovscc %icc, %f1, %f2 ++ fmovscs %icc, %f1, %f2 ++ fmovspos %icc, %f1, %f2 ++ fmovsneg %icc, %f1, %f2 ++ fmovsvc %icc, %f1, %f2 ++ fmovsvs %icc, %f1, %f2 ++ ++ ! CHECK fmovsne %xcc, %f1, %f2 ! encoding: [0x85,0xaa,0x70,0x21] ++ ! CHECK fmovse %xcc, %f1, %f2 ! encoding: [0x85,0xa8,0x70,0x21] ++ ! CHECK fmovsg %xcc, %f1, %f2 ! encoding: [0x85,0xaa,0xb0,0x21] ++ ! CHECK fmovsle %xcc, %f1, %f2 ! encoding: [0x85,0xa8,0xb0,0x21] ++ ! CHECK fmovsge %xcc, %f1, %f2 ! encoding: [0x85,0xaa,0xf0,0x21] ++ ! CHECK fmovsl %xcc, %f1, %f2 ! encoding: [0x85,0xa8,0xf0,0x21] ++ ! CHECK fmovsgu %xcc, %f1, %f2 ! encoding: [0x85,0xab,0x30,0x21] ++ ! CHECK fmovsleu %xcc, %f1, %f2 ! encoding: [0x85,0xa9,0x30,0x21] ++ ! CHECK fmovscc %xcc, %f1, %f2 ! encoding: [0x85,0xab,0x70,0x21] ++ ! CHECK fmovscs %xcc, %f1, %f2 ! encoding: [0x85,0xa9,0x70,0x21] ++ ! CHECK fmovspos %xcc, %f1, %f2 ! encoding: [0x85,0xab,0xb0,0x21] ++ ! CHECK fmovsneg %xcc, %f1, %f2 ! encoding: [0x85,0xa9,0xb0,0x21] ++ ! CHECK fmovsvc %xcc, %f1, %f2 ! encoding: [0x85,0xab,0xf0,0x21] ++ ! CHECK fmovsvs %xcc, %f1, %f2 ! encoding: [0x85,0xa9,0xf0,0x21] ++ fmovsne %xcc, %f1, %f2 ++ fmovse %xcc, %f1, %f2 ++ fmovsg %xcc, %f1, %f2 ++ fmovsle %xcc, %f1, %f2 ++ fmovsge %xcc, %f1, %f2 ++ fmovsl %xcc, %f1, %f2 ++ fmovsgu %xcc, %f1, %f2 ++ fmovsleu %xcc, %f1, %f2 ++ fmovscc %xcc, %f1, %f2 ++ fmovscs %xcc, %f1, %f2 ++ fmovspos %xcc, %f1, %f2 ++ fmovsneg %xcc, %f1, %f2 ++ fmovsvc %xcc, %f1, %f2 ++ fmovsvs %xcc, %f1, %f2 ++ ++ ! CHECK fmovsu %fcc0, %f1, %f2 ! encoding: [0x85,0xa9,0xc0,0x21] ++ ! CHECK fmovsg %fcc0, %f1, %f2 ! encoding: [0x85,0xa9,0x80,0x21] ++ ! CHECK fmovsug %fcc0, %f1, %f2 ! encoding: [0x85,0xa9,0x40,0x21] ++ ! CHECK fmovsl %fcc0, %f1, %f2 ! encoding: [0x85,0xa9,0x00,0x21] ++ ! CHECK fmovsul %fcc0, %f1, %f2 ! encoding: [0x85,0xa8,0xc0,0x21] ++ ! CHECK fmovslg %fcc0, %f1, %f2 ! encoding: [0x85,0xa8,0x80,0x21] ++ ! CHECK fmovsne %fcc0, %f1, %f2 ! encoding: [0x85,0xa8,0x40,0x21] ++ ! CHECK fmovse %fcc0, %f1, %f2 ! encoding: [0x85,0xaa,0x40,0x21] ++ ! CHECK fmovsue %fcc0, %f1, %f2 ! encoding: [0x85,0xaa,0x80,0x21] ++ ! CHECK fmovsge %fcc0, %f1, %f2 ! encoding: [0x85,0xaa,0xc0,0x21] ++ ! CHECK fmovsuge %fcc0, %f1, %f2 ! encoding: [0x85,0xab,0x00,0x21] ++ ! CHECK fmovsle %fcc0, %f1, %f2 ! encoding: [0x85,0xab,0x40,0x21] ++ ! CHECK fmovsule %fcc0, %f1, %f2 ! encoding: [0x85,0xab,0x80,0x21] ++ ! CHECK fmovso %fcc0, %f1, %f2 ! encoding: [0x85,0xab,0xc0,0x21] ++ fmovsu %fcc0, %f1, %f2 ++ fmovsg %fcc0, %f1, %f2 ++ fmovsug %fcc0, %f1, %f2 ++ fmovsl %fcc0, %f1, %f2 ++ fmovsul %fcc0, %f1, %f2 ++ fmovslg %fcc0, %f1, %f2 ++ fmovsne %fcc0, %f1, %f2 ++ fmovse %fcc0, %f1, %f2 ++ fmovsue %fcc0, %f1, %f2 ++ fmovsge %fcc0, %f1, %f2 ++ fmovsuge %fcc0, %f1, %f2 ++ fmovsle %fcc0, %f1, %f2 ++ fmovsule %fcc0, %f1, %f2 ++ fmovso %fcc0, %f1, %f2 ++ +Index: lib/Target/Sparc/SparcInstr64Bit.td +=================================================================== +--- lib/Target/Sparc/SparcInstr64Bit.td ++++ lib/Target/Sparc/SparcInstr64Bit.td +@@ -333,32 +333,42 @@ class XBranchSP<dag ins, string asmstr, list<dag> + let Predicates = [Is64Bit] in { + + let Uses = [ICC] in +-def BPXCC : XBranchSP<(ins brtarget:$imm22, CCOp:$cond), +- "b$cond %xcc, $imm22", +- [(SPbrxcc bb:$imm22, imm:$cond)]>; ++def BPXCC : XBranchSP<(ins brtarget:$imm19, CCOp:$cond), ++ "b$cond %xcc, $imm19", ++ [(SPbrxcc bb:$imm19, imm:$cond)]>; + + // Conditional moves on %xcc. + let Uses = [ICC], Constraints = "$f = $rd" in { +-def MOVXCCrr : Pseudo<(outs IntRegs:$rd), ++let cc = 0b110 in { ++def MOVXCCrr : F4_1<0b101100, (outs IntRegs:$rd), + (ins IntRegs:$rs2, IntRegs:$f, CCOp:$cond), + "mov$cond %xcc, $rs2, $rd", + [(set i32:$rd, + (SPselectxcc i32:$rs2, i32:$f, imm:$cond))]>; +-def MOVXCCri : Pseudo<(outs IntRegs:$rd), +- (ins i32imm:$i, IntRegs:$f, CCOp:$cond), +- "mov$cond %xcc, $i, $rd", ++def MOVXCCri : F4_2<0b101100, (outs IntRegs:$rd), ++ (ins i32imm:$simm11, IntRegs:$f, CCOp:$cond), ++ "mov$cond %xcc, $simm11, $rd", + [(set i32:$rd, +- (SPselectxcc simm11:$i, i32:$f, imm:$cond))]>; +-def FMOVS_XCC : Pseudo<(outs FPRegs:$rd), ++ (SPselectxcc simm11:$simm11, i32:$f, imm:$cond))]>; ++} // cc ++ ++let opf_cc = 0b110 in { ++def FMOVS_XCC : F4_3<0b110101, 0b000001, (outs FPRegs:$rd), + (ins FPRegs:$rs2, FPRegs:$f, CCOp:$cond), + "fmovs$cond %xcc, $rs2, $rd", + [(set f32:$rd, + (SPselectxcc f32:$rs2, f32:$f, imm:$cond))]>; +-def FMOVD_XCC : Pseudo<(outs DFPRegs:$rd), ++def FMOVD_XCC : F4_3<0b110101, 0b000010, (outs DFPRegs:$rd), + (ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond), + "fmovd$cond %xcc, $rs2, $rd", + [(set f64:$rd, + (SPselectxcc f64:$rs2, f64:$f, imm:$cond))]>; ++def FMOVQ_XCC : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd), ++ (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond), ++ "fmovq$cond %xcc, $rs2, $rd", ++ [(set f128:$rd, ++ (SPselectxcc f128:$rs2, f128:$f, imm:$cond))]>; ++} // opf_cc + } // Uses, Constraints + + //===----------------------------------------------------------------------===// +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -928,8 +928,9 @@ let Predicates = [HasV9], Constraints = "$f = $rd" + def FMOVQ_ICC + : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd), + (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond), +- "fmovd$cond %icc, $rs2, $rd", +- [(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>; ++ "fmovq$cond %icc, $rs2, $rd", ++ [(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>, ++ Requires<[HasHardQuad]>; + } + + let Uses = [FCC], opf_cc = 0b000 in { +@@ -946,8 +947,9 @@ let Predicates = [HasV9], Constraints = "$f = $rd" + def FMOVQ_FCC + : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd), + (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond), +- "fmovd$cond %fcc0, $rs2, $rd", +- [(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>; ++ "fmovq$cond %fcc0, $rs2, $rd", ++ [(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>, ++ Requires<[HasHardQuad]>; + } + + } +@@ -1092,3 +1094,4 @@ def : Pat<(atomic_store ADDRri:$dst, i32:$val), (S + + + include "SparcInstr64Bit.td" ++include "SparcInstrAliases.td" +Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +=================================================================== +--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp ++++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +@@ -537,9 +537,29 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand + Parser.Lex(); // Eat the '%'. + unsigned RegNo; + if (matchRegisterName(Parser.getTok(), RegNo, false, false)) { ++ StringRef name = Parser.getTok().getString(); + Parser.Lex(); // Eat the identifier token. + E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); +- Op = SparcOperand::CreateReg(RegNo, SparcOperand::rk_None, S, E); ++ switch (RegNo) { ++ default: ++ Op = SparcOperand::CreateReg(RegNo, SparcOperand::rk_None, S, E); ++ break; ++ case Sparc::Y: ++ Op = SparcOperand::CreateToken("%y", S); ++ break; ++ ++ case Sparc::ICC: ++ if (name == "xcc") ++ Op = SparcOperand::CreateToken("%xcc", S); ++ else ++ Op = SparcOperand::CreateToken("%icc", S); ++ break; ++ ++ case Sparc::FCC: ++ assert(name == "fcc0" && "Cannot handle %fcc other than %fcc0 yet"); ++ Op = SparcOperand::CreateToken("%fcc0", S); ++ break; ++ } + break; + } + if (matchSparcAsmModifiers(EVal, E)) { +Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp +=================================================================== +--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp ++++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp +@@ -83,6 +83,17 @@ void SparcInstPrinter::printCCOperand(const MCInst + raw_ostream &O) + { + int CC = (int)MI->getOperand(opNum).getImm(); ++ switch (MI->getOpcode()) { ++ default: break; ++ case SP::FBCOND: ++ case SP::MOVFCCrr: ++ case SP::MOVFCCri: ++ case SP::FMOVS_FCC: ++ case SP::FMOVD_FCC: ++ case SP::FMOVQ_FCC: // Make sure CC is a fp conditional flag. ++ CC = (CC < 16) ? (CC + 16) : CC; ++ break; ++ } + O << SPARCCondCodeToString((SPCC::CondCodes)CC); + } + +Index: lib/Target/Sparc/SparcInstrAliases.td +=================================================================== +--- lib/Target/Sparc/SparcInstrAliases.td ++++ lib/Target/Sparc/SparcInstrAliases.td +@@ -0,0 +1,119 @@ ++//===-- SparcInstrAliases.td - Instruction Aliases for Sparc Target -------===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++// ++// This file contains instruction aliases for Sparc. ++//===----------------------------------------------------------------------===// ++ ++// Instruction aliases for conditional moves. ++ ++// mov<cond> <ccreg> rs2, rd ++multiclass cond_mov_alias<string cond, int condVal, string ccreg, ++ Instruction movrr, Instruction movri, ++ Instruction fmovs, Instruction fmovd> { ++ ++ // mov<cond> (%icc|%xcc|%fcc0), rs2, rd ++ def : InstAlias<!strconcat(!strconcat(!strconcat("mov", cond), ccreg), ++ ", $rs2, $rd"), ++ (movrr IntRegs:$rd, IntRegs:$rs2, condVal)>; ++ ++ // mov<cond> (%icc|%xcc|%fcc0), simm11, rd ++ def : InstAlias<!strconcat(!strconcat(!strconcat("mov", cond), ccreg), ++ ", $simm11, $rd"), ++ (movri IntRegs:$rd, i32imm:$simm11, condVal)>; ++ ++ // fmovs<cond> (%icc|%xcc|%fcc0), $rs2, $rd ++ def : InstAlias<!strconcat(!strconcat(!strconcat("fmovs", cond), ccreg), ++ ", $rs2, $rd"), ++ (fmovs FPRegs:$rd, FPRegs:$rs2, condVal)>; ++ ++ // fmovd<cond> (%icc|%xcc|%fcc0), $rs2, $rd ++ def : InstAlias<!strconcat(!strconcat(!strconcat("fmovd", cond), ccreg), ++ ", $rs2, $rd"), ++ (fmovd DFPRegs:$rd, DFPRegs:$rs2, condVal)>; ++} ++ ++ ++// Instruction aliases for integer conditional branches and moves. ++multiclass int_cond_alias<string cond, int condVal> { ++ ++ // b<cond> $imm ++ def : InstAlias<!strconcat(!strconcat("b", cond), " $imm"), ++ (BCOND brtarget:$imm, condVal)>; ++ ++ // b<cond> %xcc, $imm ++ def : InstAlias<!strconcat(!strconcat("b", cond), " %xcc, $imm"), ++ (BPXCC brtarget:$imm, condVal)>, Requires<[Is64Bit]>; ++ ++ defm : cond_mov_alias<cond, condVal, " %icc", ++ MOVICCrr, MOVICCri, ++ FMOVS_ICC, FMOVD_ICC>, Requires<[HasV9]>; ++ ++ defm : cond_mov_alias<cond, condVal, " %xcc", ++ MOVXCCrr, MOVXCCri, ++ FMOVS_XCC, FMOVD_XCC>, Requires<[Is64Bit]>; ++ ++ // fmovq<cond> (%icc|%xcc), $rs2, $rd ++ def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %icc, $rs2, $rd"), ++ (FMOVQ_ICC QFPRegs:$rd, QFPRegs:$rs2, condVal)>, ++ Requires<[HasV9, HasHardQuad]>; ++ def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %xcc, $rs2, $rd"), ++ (FMOVQ_XCC QFPRegs:$rd, QFPRegs:$rs2, condVal)>, ++ Requires<[Is64Bit, HasHardQuad]>; ++ ++} ++ ++ ++// Instruction aliases for floating point conditional branches and moves. ++multiclass fp_cond_alias<string cond, int condVal> { ++ ++ // fb<cond> $imm ++ def : InstAlias<!strconcat(!strconcat("fb", cond), " $imm"), ++ (FBCOND brtarget:$imm, condVal), 0>; ++ ++ defm : cond_mov_alias<cond, condVal, " %fcc0", ++ MOVFCCrr, MOVFCCri, ++ FMOVS_FCC, FMOVD_FCC>, Requires<[HasV9]>; ++ ++ // fmovq<cond> %fcc0, $rs2, $rd ++ def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %fcc0, $rs2, $rd"), ++ (FMOVQ_ICC QFPRegs:$rd, QFPRegs:$rs2, condVal)>, ++ Requires<[HasV9, HasHardQuad]>; ++} ++ ++defm : int_cond_alias<"a", 0b1000>; ++defm : int_cond_alias<"n", 0b0000>; ++defm : int_cond_alias<"ne", 0b1001>; ++defm : int_cond_alias<"e", 0b0001>; ++defm : int_cond_alias<"g", 0b1010>; ++defm : int_cond_alias<"le", 0b0010>; ++defm : int_cond_alias<"ge", 0b1011>; ++defm : int_cond_alias<"l", 0b0011>; ++defm : int_cond_alias<"gu", 0b1100>; ++defm : int_cond_alias<"leu", 0b0100>; ++defm : int_cond_alias<"cc", 0b1101>; ++defm : int_cond_alias<"cs", 0b0101>; ++defm : int_cond_alias<"pos", 0b1110>; ++defm : int_cond_alias<"neg", 0b0110>; ++defm : int_cond_alias<"vc", 0b1111>; ++defm : int_cond_alias<"vs", 0b0111>; ++ ++defm : fp_cond_alias<"u", 0b0111>; ++defm : fp_cond_alias<"g", 0b0110>; ++defm : fp_cond_alias<"ug", 0b0101>; ++defm : fp_cond_alias<"l", 0b0100>; ++defm : fp_cond_alias<"ul", 0b0011>; ++defm : fp_cond_alias<"lg", 0b0010>; ++defm : fp_cond_alias<"ne", 0b0001>; ++defm : fp_cond_alias<"e", 0b1001>; ++defm : fp_cond_alias<"ue", 0b1010>; ++defm : fp_cond_alias<"ge", 0b1011>; ++defm : fp_cond_alias<"uge", 0b1100>; ++defm : fp_cond_alias<"le", 0b1101>; ++defm : fp_cond_alias<"ule", 0b1110>; ++defm : fp_cond_alias<"o", 0b1111>; diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198739-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198739-sparc.diff new file mode 100644 index 0000000..f7b884c --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198739-sparc.diff @@ -0,0 +1,19 @@ +Pull in r198739 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Correct the mask for fixup_sparc_br19. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +@@ -31,7 +31,7 @@ static unsigned adjustFixupValue(unsigned Kind, ui + case Sparc::fixup_sparc_br22: + return (Value >> 2) & 0x3fffff; + case Sparc::fixup_sparc_br19: +- return (Value >> 2) & 0x1ffff; ++ return (Value >> 2) & 0x7ffff; + case Sparc::fixup_sparc_hi22: + return (Value >> 10) & 0x3fffff; + case Sparc::fixup_sparc_lo10: diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198740-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198740-sparc.diff new file mode 100644 index 0000000..ff9bfd5 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198740-sparc.diff @@ -0,0 +1,115 @@ +Pull in r198740 from upstream llvm trunk (by Venkatraman Govindaraju): + + [SparcV9] Rename operands in some sparc64 instructions so that TableGen can encode them correctly. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/MC/Sparc/sparc64-alu-instructions.s +=================================================================== +--- test/MC/Sparc/sparc64-alu-instructions.s ++++ test/MC/Sparc/sparc64-alu-instructions.s +@@ -0,0 +1,38 @@ ++! RUN: llvm-mc %s -triple=sparc64-unknown-linux-gnu -show-encoding | FileCheck %s ++ ++ ! CHECK: sllx %g1, %i2, %i0 ! encoding: [0xb1,0x28,0x50,0x1a] ++ sllx %g1, %i2, %i0 ++ ++ ! CHECK: sllx %g1, 63, %i0 ! encoding: [0xb1,0x28,0x70,0x3f] ++ sllx %g1, 63, %i0 ++ ++ ! CHECK: srlx %g1, %i2, %i0 ! encoding: [0xb1,0x30,0x50,0x1a] ++ srlx %g1, %i2, %i0 ++ ++ ! CHECK: srlx %g1, 63, %i0 ! encoding: [0xb1,0x30,0x70,0x3f] ++ srlx %g1, 63, %i0 ++ ++ ! CHECK: srax %g1, %i2, %i0 ! encoding: [0xb1,0x38,0x50,0x1a] ++ srax %g1, %i2, %i0 ++ ++ ! CHECK: srax %g1, 63, %i0 ! encoding: [0xb1,0x38,0x70,0x3f] ++ srax %g1, 63, %i0 ++ ++ ! CHECK: mulx %g1, %i2, %i0 ! encoding: [0xb0,0x48,0x40,0x1a] ++ mulx %g1, %i2, %i0 ++ ++ ! CHECK: mulx %g1, 63, %i0 ! encoding: [0xb0,0x48,0x60,0x3f] ++ mulx %g1, 63, %i0 ++ ++ ! CHECK: sdivx %g1, %i2, %i0 ! encoding: [0xb1,0x68,0x40,0x1a] ++ sdivx %g1, %i2, %i0 ++ ++ ! CHECK: sdivx %g1, 63, %i0 ! encoding: [0xb1,0x68,0x60,0x3f] ++ sdivx %g1, 63, %i0 ++ ++ ! CHECK: udivx %g1, %i2, %i0 ! encoding: [0xb0,0x68,0x40,0x1a] ++ udivx %g1, %i2, %i0 ++ ++ ! CHECK: udivx %g1, 63, %i0 ! encoding: [0xb0,0x68,0x60,0x3f] ++ udivx %g1, 63, %i0 ++ +Index: lib/Target/Sparc/SparcInstr64Bit.td +=================================================================== +--- lib/Target/Sparc/SparcInstr64Bit.td ++++ lib/Target/Sparc/SparcInstr64Bit.td +@@ -193,9 +193,9 @@ def MULXrr : F3_1<2, 0b001001, + "mulx $rs1, $rs2, $rd", + [(set i64:$rd, (mul i64:$rs1, i64:$rs2))]>; + def MULXri : F3_2<2, 0b001001, +- (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$i), +- "mulx $rs1, $i, $rd", +- [(set i64:$rd, (mul i64:$rs1, (i64 simm13:$i)))]>; ++ (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13), ++ "mulx $rs1, $simm13, $rd", ++ [(set i64:$rd, (mul i64:$rs1, (i64 simm13:$simm13)))]>; + + // Division can trap. + let hasSideEffects = 1 in { +@@ -204,9 +204,9 @@ def SDIVXrr : F3_1<2, 0b101101, + "sdivx $rs1, $rs2, $rd", + [(set i64:$rd, (sdiv i64:$rs1, i64:$rs2))]>; + def SDIVXri : F3_2<2, 0b101101, +- (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$i), +- "sdivx $rs1, $i, $rd", +- [(set i64:$rd, (sdiv i64:$rs1, (i64 simm13:$i)))]>; ++ (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13), ++ "sdivx $rs1, $simm13, $rd", ++ [(set i64:$rd, (sdiv i64:$rs1, (i64 simm13:$simm13)))]>; + + def UDIVXrr : F3_1<2, 0b001101, + (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2), +@@ -213,9 +213,9 @@ def UDIVXrr : F3_1<2, 0b001101, + "udivx $rs1, $rs2, $rd", + [(set i64:$rd, (udiv i64:$rs1, i64:$rs2))]>; + def UDIVXri : F3_2<2, 0b001101, +- (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$i), +- "udivx $rs1, $i, $rd", +- [(set i64:$rd, (udiv i64:$rs1, (i64 simm13:$i)))]>; ++ (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13), ++ "udivx $rs1, $simm13, $rd", ++ [(set i64:$rd, (udiv i64:$rs1, (i64 simm13:$simm13)))]>; + } // hasSideEffects = 1 + + } // Predicates = [Is64Bit] +Index: lib/Target/Sparc/SparcInstrFormats.td +=================================================================== +--- lib/Target/Sparc/SparcInstrFormats.td ++++ lib/Target/Sparc/SparcInstrFormats.td +@@ -193,12 +193,12 @@ class F3_Si<bits<2> opVal, bits<6> op3val, bit xVa + // Define rr and ri shift instructions with patterns. + multiclass F3_S<string OpcStr, bits<6> Op3Val, bit XVal, SDNode OpNode, + ValueType VT, RegisterClass RC> { +- def rr : F3_Sr<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs, IntRegs:$rs2), +- !strconcat(OpcStr, " $rs, $rs2, $rd"), +- [(set VT:$rd, (OpNode VT:$rs, i32:$rs2))]>; +- def ri : F3_Si<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs, i32imm:$shcnt), +- !strconcat(OpcStr, " $rs, $shcnt, $rd"), +- [(set VT:$rd, (OpNode VT:$rs, (i32 imm:$shcnt)))]>; ++ def rr : F3_Sr<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, IntRegs:$rs2), ++ !strconcat(OpcStr, " $rs1, $rs2, $rd"), ++ [(set VT:$rd, (OpNode VT:$rs1, i32:$rs2))]>; ++ def ri : F3_Si<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, i32imm:$shcnt), ++ !strconcat(OpcStr, " $rs1, $shcnt, $rd"), ++ [(set VT:$rd, (OpNode VT:$rs1, (i32 imm:$shcnt)))]>; + } + + class F4<bits<6> op3, dag outs, dag ins, string asmstr, list<dag> pattern> diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198893-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198893-sparc.diff new file mode 100644 index 0000000..a1434c0 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198893-sparc.diff @@ -0,0 +1,236 @@ +Pull in r198893 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Multiclass for loads/stores. No functionality change intended. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcInstr64Bit.td +=================================================================== +--- lib/Target/Sparc/SparcInstr64Bit.td ++++ lib/Target/Sparc/SparcInstr64Bit.td +@@ -235,14 +235,8 @@ def UDIVXri : F3_2<2, 0b001101, + let Predicates = [Is64Bit] in { + + // 64-bit loads. +-def LDXrr : F3_1<3, 0b001011, +- (outs I64Regs:$dst), (ins MEMrr:$addr), +- "ldx [$addr], $dst", +- [(set i64:$dst, (load ADDRrr:$addr))]>; +-def LDXri : F3_2<3, 0b001011, +- (outs I64Regs:$dst), (ins MEMri:$addr), +- "ldx [$addr], $dst", +- [(set i64:$dst, (load ADDRri:$addr))]>; ++defm LDX : Load<"ldx", 0b001011, load, I64Regs, i64>; ++ + let mayLoad = 1, isCodeGenOnly = 1, isAsmParserOnly = 1 in + def TLS_LDXrr : F3_1<3, 0b001011, + (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym), +@@ -276,24 +270,10 @@ def : Pat<(i64 (extloadi32 ADDRrr:$addr)), (LDrr + def : Pat<(i64 (extloadi32 ADDRri:$addr)), (LDri ADDRri:$addr)>; + + // Sign-extending load of i32 into i64 is a new SPARC v9 instruction. +-def LDSWrr : F3_1<3, 0b001000, +- (outs I64Regs:$dst), (ins MEMrr:$addr), +- "ldsw [$addr], $dst", +- [(set i64:$dst, (sextloadi32 ADDRrr:$addr))]>; +-def LDSWri : F3_2<3, 0b001000, +- (outs I64Regs:$dst), (ins MEMri:$addr), +- "ldsw [$addr], $dst", +- [(set i64:$dst, (sextloadi32 ADDRri:$addr))]>; ++defm LDSW : Load<"ldsw", 0b001000, sextloadi32, I64Regs, i64>; + + // 64-bit stores. +-def STXrr : F3_1<3, 0b001110, +- (outs), (ins MEMrr:$addr, I64Regs:$rd), +- "stx $rd, [$addr]", +- [(store i64:$rd, ADDRrr:$addr)]>; +-def STXri : F3_2<3, 0b001110, +- (outs), (ins MEMri:$addr, I64Regs:$rd), +- "stx $rd, [$addr]", +- [(store i64:$rd, ADDRri:$addr)]>; ++defm STX : Store<"stx", 0b001110, store, I64Regs, i64>; + + // Truncating stores from i64 are identical to the i32 stores. + def : Pat<(truncstorei8 i64:$src, ADDRrr:$addr), (STBrr ADDRrr:$addr, $src)>; +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -250,6 +250,32 @@ multiclass F3_12np<string OpcStr, bits<6> Op3Val> + !strconcat(OpcStr, " $rs1, $simm13, $rd"), []>; + } + ++// Load multiclass - Define both Reg+Reg/Reg+Imm patterns in one shot. ++multiclass Load<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode, ++ RegisterClass RC, ValueType Ty> { ++ def rr : F3_1<3, Op3Val, ++ (outs RC:$dst), (ins MEMrr:$addr), ++ !strconcat(OpcStr, " [$addr], $dst"), ++ [(set Ty:$dst, (OpNode ADDRrr:$addr))]>; ++ def ri : F3_2<3, Op3Val, ++ (outs RC:$dst), (ins MEMri:$addr), ++ !strconcat(OpcStr, " [$addr], $dst"), ++ [(set Ty:$dst, (OpNode ADDRri:$addr))]>; ++} ++ ++// Store multiclass - Define both Reg+Reg/Reg+Imm patterns in one shot. ++multiclass Store<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode, ++ RegisterClass RC, ValueType Ty> { ++ def rr : F3_1<3, Op3Val, ++ (outs), (ins MEMrr:$addr, RC:$rd), ++ !strconcat(OpcStr, " $rd, [$addr]"), ++ [(OpNode Ty:$rd, ADDRrr:$addr)]>; ++ def ri : F3_2<3, Op3Val, ++ (outs), (ins MEMri:$addr, RC:$rd), ++ !strconcat(OpcStr, " $rd, [$addr]"), ++ [(OpNode Ty:$rd, ADDRri:$addr)]>; ++} ++ + //===----------------------------------------------------------------------===// + // Instructions + //===----------------------------------------------------------------------===// +@@ -350,128 +376,28 @@ let isReturn = 1, isTerminator = 1, hasDelaySlot = + } + + // Section B.1 - Load Integer Instructions, p. 90 +-def LDSBrr : F3_1<3, 0b001001, +- (outs IntRegs:$dst), (ins MEMrr:$addr), +- "ldsb [$addr], $dst", +- [(set i32:$dst, (sextloadi8 ADDRrr:$addr))]>; +-def LDSBri : F3_2<3, 0b001001, +- (outs IntRegs:$dst), (ins MEMri:$addr), +- "ldsb [$addr], $dst", +- [(set i32:$dst, (sextloadi8 ADDRri:$addr))]>; +-def LDSHrr : F3_1<3, 0b001010, +- (outs IntRegs:$dst), (ins MEMrr:$addr), +- "ldsh [$addr], $dst", +- [(set i32:$dst, (sextloadi16 ADDRrr:$addr))]>; +-def LDSHri : F3_2<3, 0b001010, +- (outs IntRegs:$dst), (ins MEMri:$addr), +- "ldsh [$addr], $dst", +- [(set i32:$dst, (sextloadi16 ADDRri:$addr))]>; +-def LDUBrr : F3_1<3, 0b000001, +- (outs IntRegs:$dst), (ins MEMrr:$addr), +- "ldub [$addr], $dst", +- [(set i32:$dst, (zextloadi8 ADDRrr:$addr))]>; +-def LDUBri : F3_2<3, 0b000001, +- (outs IntRegs:$dst), (ins MEMri:$addr), +- "ldub [$addr], $dst", +- [(set i32:$dst, (zextloadi8 ADDRri:$addr))]>; +-def LDUHrr : F3_1<3, 0b000010, +- (outs IntRegs:$dst), (ins MEMrr:$addr), +- "lduh [$addr], $dst", +- [(set i32:$dst, (zextloadi16 ADDRrr:$addr))]>; +-def LDUHri : F3_2<3, 0b000010, +- (outs IntRegs:$dst), (ins MEMri:$addr), +- "lduh [$addr], $dst", +- [(set i32:$dst, (zextloadi16 ADDRri:$addr))]>; +-def LDrr : F3_1<3, 0b000000, +- (outs IntRegs:$dst), (ins MEMrr:$addr), +- "ld [$addr], $dst", +- [(set i32:$dst, (load ADDRrr:$addr))]>; +-def LDri : F3_2<3, 0b000000, +- (outs IntRegs:$dst), (ins MEMri:$addr), +- "ld [$addr], $dst", +- [(set i32:$dst, (load ADDRri:$addr))]>; ++defm LDSB : Load<"ldsb", 0b001001, sextloadi8, IntRegs, i32>; ++defm LDSH : Load<"ldsh", 0b001010, sextloadi16, IntRegs, i32>; ++defm LDUB : Load<"ldub", 0b000001, zextloadi8, IntRegs, i32>; ++defm LDUH : Load<"lduh", 0b000010, zextloadi16, IntRegs, i32>; ++defm LD : Load<"ld", 0b000000, load, IntRegs, i32>; + + // Section B.2 - Load Floating-point Instructions, p. 92 +-def LDFrr : F3_1<3, 0b100000, +- (outs FPRegs:$dst), (ins MEMrr:$addr), +- "ld [$addr], $dst", +- [(set f32:$dst, (load ADDRrr:$addr))]>; +-def LDFri : F3_2<3, 0b100000, +- (outs FPRegs:$dst), (ins MEMri:$addr), +- "ld [$addr], $dst", +- [(set f32:$dst, (load ADDRri:$addr))]>; +-def LDDFrr : F3_1<3, 0b100011, +- (outs DFPRegs:$dst), (ins MEMrr:$addr), +- "ldd [$addr], $dst", +- [(set f64:$dst, (load ADDRrr:$addr))]>; +-def LDDFri : F3_2<3, 0b100011, +- (outs DFPRegs:$dst), (ins MEMri:$addr), +- "ldd [$addr], $dst", +- [(set f64:$dst, (load ADDRri:$addr))]>; +-def LDQFrr : F3_1<3, 0b100010, +- (outs QFPRegs:$dst), (ins MEMrr:$addr), +- "ldq [$addr], $dst", +- [(set f128:$dst, (load ADDRrr:$addr))]>, +- Requires<[HasV9, HasHardQuad]>; +-def LDQFri : F3_2<3, 0b100010, +- (outs QFPRegs:$dst), (ins MEMri:$addr), +- "ldq [$addr], $dst", +- [(set f128:$dst, (load ADDRri:$addr))]>, +- Requires<[HasV9, HasHardQuad]>; ++defm LDF : Load<"ld", 0b100000, load, FPRegs, f32>; ++defm LDDF : Load<"ldd", 0b100011, load, DFPRegs, f64>; ++defm LDQF : Load<"ldq", 0b100010, load, QFPRegs, f128>, ++ Requires<[HasV9, HasHardQuad]>; + + // Section B.4 - Store Integer Instructions, p. 95 +-def STBrr : F3_1<3, 0b000101, +- (outs), (ins MEMrr:$addr, IntRegs:$rd), +- "stb $rd, [$addr]", +- [(truncstorei8 i32:$rd, ADDRrr:$addr)]>; +-def STBri : F3_2<3, 0b000101, +- (outs), (ins MEMri:$addr, IntRegs:$rd), +- "stb $rd, [$addr]", +- [(truncstorei8 i32:$rd, ADDRri:$addr)]>; +-def STHrr : F3_1<3, 0b000110, +- (outs), (ins MEMrr:$addr, IntRegs:$rd), +- "sth $rd, [$addr]", +- [(truncstorei16 i32:$rd, ADDRrr:$addr)]>; +-def STHri : F3_2<3, 0b000110, +- (outs), (ins MEMri:$addr, IntRegs:$rd), +- "sth $rd, [$addr]", +- [(truncstorei16 i32:$rd, ADDRri:$addr)]>; +-def STrr : F3_1<3, 0b000100, +- (outs), (ins MEMrr:$addr, IntRegs:$rd), +- "st $rd, [$addr]", +- [(store i32:$rd, ADDRrr:$addr)]>; +-def STri : F3_2<3, 0b000100, +- (outs), (ins MEMri:$addr, IntRegs:$rd), +- "st $rd, [$addr]", +- [(store i32:$rd, ADDRri:$addr)]>; ++defm STB : Store<"stb", 0b000101, truncstorei8, IntRegs, i32>; ++defm STH : Store<"sth", 0b000110, truncstorei16, IntRegs, i32>; ++defm ST : Store<"st", 0b000100, store, IntRegs, i32>; + + // Section B.5 - Store Floating-point Instructions, p. 97 +-def STFrr : F3_1<3, 0b100100, +- (outs), (ins MEMrr:$addr, FPRegs:$rd), +- "st $rd, [$addr]", +- [(store f32:$rd, ADDRrr:$addr)]>; +-def STFri : F3_2<3, 0b100100, +- (outs), (ins MEMri:$addr, FPRegs:$rd), +- "st $rd, [$addr]", +- [(store f32:$rd, ADDRri:$addr)]>; +-def STDFrr : F3_1<3, 0b100111, +- (outs), (ins MEMrr:$addr, DFPRegs:$rd), +- "std $rd, [$addr]", +- [(store f64:$rd, ADDRrr:$addr)]>; +-def STDFri : F3_2<3, 0b100111, +- (outs), (ins MEMri:$addr, DFPRegs:$rd), +- "std $rd, [$addr]", +- [(store f64:$rd, ADDRri:$addr)]>; +-def STQFrr : F3_1<3, 0b100110, +- (outs), (ins MEMrr:$addr, QFPRegs:$rd), +- "stq $rd, [$addr]", +- [(store f128:$rd, ADDRrr:$addr)]>, +- Requires<[HasV9, HasHardQuad]>; +-def STQFri : F3_2<3, 0b100110, +- (outs), (ins MEMri:$addr, QFPRegs:$rd), +- "stq $rd, [$addr]", +- [(store f128:$rd, ADDRri:$addr)]>, +- Requires<[HasV9, HasHardQuad]>; ++defm STF : Store<"st", 0b100100, store, FPRegs, f32>; ++defm STDF : Store<"std", 0b100111, store, DFPRegs, f64>; ++defm STQF : Store<"stq", 0b100110, store, QFPRegs, f128>, ++ Requires<[HasV9, HasHardQuad]>; + + // Section B.9 - SETHI Instruction, p. 104 + def SETHIi: F2_1<0b100, diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198909-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198909-sparc.diff new file mode 100644 index 0000000..e4fb0f3 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198909-sparc.diff @@ -0,0 +1,229 @@ +Pull in r198909 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add support for parsing jmpl instruction and make indirect call and jmp instructions as aliases to jmpl. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +=================================================================== +--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp ++++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +@@ -453,6 +453,7 @@ parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand + switch (getLexer().getKind()) { + default: return MatchOperand_NoMatch; + ++ case AsmToken::Comma: + case AsmToken::RBrac: + case AsmToken::EndOfStatement: + Operands.push_back(SparcOperand::CreateMEMri(BaseReg, 0, S, E)); +Index: lib/Target/Sparc/SparcInstrAliases.td +=================================================================== +--- lib/Target/Sparc/SparcInstrAliases.td ++++ lib/Target/Sparc/SparcInstrAliases.td +@@ -117,3 +117,14 @@ defm : fp_cond_alias<"uge", 0b1100>; + defm : fp_cond_alias<"le", 0b1101>; + defm : fp_cond_alias<"ule", 0b1110>; + defm : fp_cond_alias<"o", 0b1111>; ++ ++ ++// Instruction aliases for JMPL. ++ ++// jmp addr -> jmpl addr, %g0 ++def : InstAlias<"jmp $addr", (JMPLrr G0, MEMrr:$addr)>; ++def : InstAlias<"jmp $addr", (JMPLri G0, MEMri:$addr)>; ++ ++// call addr -> jmpl addr, %o7 ++def : InstAlias<"call $addr", (JMPLrr O7, MEMrr:$addr)>; ++def : InstAlias<"call $addr", (JMPLri O7, MEMri:$addr)>; +Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp +=================================================================== +--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp ++++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp +@@ -23,6 +23,7 @@ + using namespace llvm; + + #define GET_INSTRUCTION_NAME ++#define PRINT_ALIAS_INSTR + #include "SparcGenAsmWriter.inc" + + void SparcInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const +@@ -33,10 +34,34 @@ void SparcInstPrinter::printRegName(raw_ostream &O + void SparcInstPrinter::printInst(const MCInst *MI, raw_ostream &O, + StringRef Annot) + { +- printInstruction(MI, O); ++ if (!printAliasInstr(MI, O) && !printSparcAliasInstr(MI, O)) ++ printInstruction(MI, O); + printAnnotation(O, Annot); + } + ++bool SparcInstPrinter::printSparcAliasInstr(const MCInst *MI, raw_ostream &O) ++{ ++ switch (MI->getOpcode()) { ++ default: return false; ++ case SP::JMPLrr: ++ case SP::JMPLri: { ++ if (MI->getNumOperands() != 3) ++ return false; ++ if (!MI->getOperand(0).isReg()) ++ return false; ++ switch (MI->getOperand(0).getReg()) { ++ default: return false; ++ case SP::G0: // jmp $addr ++ O << "\tjmp "; printMemOperand(MI, 1, O); ++ return true; ++ case SP::O7: // call $addr ++ O << "\tcall "; printMemOperand(MI, 1, O); ++ return true; ++ } ++ } ++ } ++} ++ + void SparcInstPrinter::printOperand(const MCInst *MI, int opNum, + raw_ostream &O) + { +Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.h +=================================================================== +--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.h ++++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.h +@@ -29,9 +29,11 @@ class SparcInstPrinter : public MCInstPrinter { + + virtual void printRegName(raw_ostream &OS, unsigned RegNo) const; + virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot); ++ bool printSparcAliasInstr(const MCInst *MI, raw_ostream &OS); + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI, raw_ostream &O); ++ bool printAliasInstr(const MCInst *MI, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + + void printOperand(const MCInst *MI, int opNum, raw_ostream &OS); +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -362,10 +362,18 @@ let usesCustomInserter = 1, Uses = [FCC] in { + [(set f128:$dst, (SPselectfcc f128:$T, f128:$F, imm:$Cond))]>; + } + ++// JMPL Instruction. ++let isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 in { ++ def JMPLrr: F3_1<2, 0b111000, (outs IntRegs:$dst), (ins MEMrr:$addr), ++ "jmpl $addr, $dst", []>; ++ def JMPLri: F3_2<2, 0b111000, (outs IntRegs:$dst), (ins MEMri:$addr), ++ "jmpl $addr, $dst", []>; ++} + + // Section A.3 - Synthetic Instructions, p. 85 + // special cases of JMPL: +-let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 in { ++let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1, ++ isCodeGenOnly = 1 in { + let rd = 0, rs1 = 15 in + def RETL: F3_2<2, 0b111000, (outs), (ins i32imm:$val), + "jmp %o7+$val", [(retflag simm13:$val)]>; +@@ -519,9 +527,8 @@ class BranchSP<dag ins, string asmstr, list<dag> p + } + + // Indirect branch instructions. +-let isTerminator = 1, isBarrier = 1, +- hasDelaySlot = 1, isBranch =1, +- isIndirectBranch = 1, rd = 0 in { ++let isTerminator = 1, isBarrier = 1, hasDelaySlot = 1, isBranch =1, ++ isIndirectBranch = 1, rd = 0, isCodeGenOnly = 1 in { + def BINDrr : F3_1<2, 0b111000, + (outs), (ins MEMrr:$ptr), + "jmp $ptr", +@@ -564,15 +571,17 @@ let Uses = [O6], + let Inst{29-0} = disp; + } + +- // indirect calls +- def JMPLrr : F3_1<2, 0b111000, +- (outs), (ins MEMrr:$ptr, variable_ops), +- "call $ptr", +- [(call ADDRrr:$ptr)]> { let rd = 15; } +- def JMPLri : F3_2<2, 0b111000, +- (outs), (ins MEMri:$ptr, variable_ops), +- "call $ptr", +- [(call ADDRri:$ptr)]> { let rd = 15; } ++ // indirect calls: special cases of JMPL. ++ let isCodeGenOnly = 1, rd = 15 in { ++ def CALLrr : F3_1<2, 0b111000, ++ (outs), (ins MEMrr:$ptr, variable_ops), ++ "call $ptr", ++ [(call ADDRrr:$ptr)]>; ++ def CALLri : F3_2<2, 0b111000, ++ (outs), (ins MEMri:$ptr, variable_ops), ++ "call $ptr", ++ [(call ADDRri:$ptr)]>; ++ } + } + + // Section B.28 - Read State Register Instructions +Index: lib/Target/Sparc/DelaySlotFiller.cpp +=================================================================== +--- lib/Target/Sparc/DelaySlotFiller.cpp ++++ lib/Target/Sparc/DelaySlotFiller.cpp +@@ -278,19 +278,19 @@ void Filler::insertCallDefsUses(MachineBasicBlock: + switch(MI->getOpcode()) { + default: llvm_unreachable("Unknown opcode."); + case SP::CALL: break; +- case SP::JMPLrr: +- case SP::JMPLri: ++ case SP::CALLrr: ++ case SP::CALLri: + assert(MI->getNumOperands() >= 2); + const MachineOperand &Reg = MI->getOperand(0); +- assert(Reg.isReg() && "JMPL first operand is not a register."); +- assert(Reg.isUse() && "JMPL first operand is not a use."); ++ assert(Reg.isReg() && "CALL first operand is not a register."); ++ assert(Reg.isUse() && "CALL first operand is not a use."); + RegUses.insert(Reg.getReg()); + + const MachineOperand &RegOrImm = MI->getOperand(1); + if (RegOrImm.isImm()) + break; +- assert(RegOrImm.isReg() && "JMPLrr second operand is not a register."); +- assert(RegOrImm.isUse() && "JMPLrr second operand is not a use."); ++ assert(RegOrImm.isReg() && "CALLrr second operand is not a register."); ++ assert(RegOrImm.isUse() && "CALLrr second operand is not a use."); + RegUses.insert(RegOrImm.getReg()); + break; + } +@@ -353,8 +353,8 @@ bool Filler::needsUnimp(MachineBasicBlock::iterato + switch (I->getOpcode()) { + default: llvm_unreachable("Unknown call opcode."); + case SP::CALL: structSizeOpNum = 1; break; +- case SP::JMPLrr: +- case SP::JMPLri: structSizeOpNum = 2; break; ++ case SP::CALLrr: ++ case SP::CALLri: structSizeOpNum = 2; break; + case SP::TLS_CALL: return false; + } + +Index: test/MC/Sparc/sparc-ctrl-instructions.s +=================================================================== +--- test/MC/Sparc/sparc-ctrl-instructions.s ++++ test/MC/Sparc/sparc-ctrl-instructions.s +@@ -31,6 +31,19 @@ + ! CHECK-NEXT: ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10 + jmp %g1+%lo(sym) + ++ ! CHECK: jmpl %g1+%i2, %g2 ! encoding: [0x85,0xc0,0x40,0x1a] ++ jmpl %g1 + %i2, %g2 ++ ++ ! CHECK: jmpl %o1+8, %g2 ! encoding: [0x85,0xc2,0x60,0x08] ++ jmpl %o1 + 8, %g2 ++ ++ ! CHECK: jmpl %g1, %g2 ! encoding: [0x85,0xc0,0x60,0x00] ++ jmpl %g1, %g2 ++ ++ ! CHECK: jmpl %g1+%lo(sym), %g2 ! encoding: [0x85,0xc0,0b011000AA,A] ++ ! CHECK-NEXT: ! fixup A - offset: 0, value: %lo(sym), kind: fixup_sparc_lo10 ++ jmpl %g1+%lo(sym), %g2 ++ + ! CHECK: ba .BB0 ! encoding: [0x10,0b10AAAAAA,A,A] + ! CHECK-NEXT: ! fixup A - offset: 0, value: .BB0, kind: fixup_sparc_br22 + ba .BB0 diff --git a/contrib/llvm/patches/patch-r262261-llvm-r198910-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r198910-sparc.diff new file mode 100644 index 0000000..94b320c --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r198910-sparc.diff @@ -0,0 +1,463 @@ +Pull in r198910 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Emit retl/ret instead of jmp instruction. It improves the readability of the assembly generated. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/CodeGen/SPARC/ctpop.ll +=================================================================== +--- test/CodeGen/SPARC/ctpop.ll ++++ test/CodeGen/SPARC/ctpop.ll +@@ -9,12 +9,12 @@ declare i32 @llvm.ctpop.i32(i32) + + ; V9-LABEL: test + ; V9: srl %o0, 0, %o0 +-; V9-NEXT: jmp %o7+8 ++; V9-NEXT: retl + ; V9-NEXT: popc %o0, %o0 + + ; SPARC64-LABEL: test + ; SPARC64: srl %o0, 0, %o0 +-; SPARC64: jmp %o7+8 ++; SPARC64: retl + ; SPARC64: popc %o0, %o0 + + define i32 @test(i32 %X) { +Index: test/CodeGen/SPARC/2011-01-11-Call.ll +=================================================================== +--- test/CodeGen/SPARC/2011-01-11-Call.ll ++++ test/CodeGen/SPARC/2011-01-11-Call.ll +@@ -8,7 +8,7 @@ + ; V8-NEXT: nop + ; V8: call bar + ; V8-NEXT: nop +-; V8: jmp %i7+8 ++; V8: ret + ; V8-NEXT: restore + + ; V9-LABEL: test +@@ -17,7 +17,7 @@ + ; V9-NEXT: nop + ; V9: call bar + ; V9-NEXT: nop +-; V9: jmp %i7+8 ++; V9: ret + ; V9-NEXT: restore + + define void @test() nounwind { +@@ -36,7 +36,7 @@ declare void @bar(...) + ; V8: save %sp + ; V8: call foo + ; V8-NEXT: nop +-; V8: jmp %i7+8 ++; V8: ret + ; V8-NEXT: restore %g0, %o0, %o0 + + ; V9-LABEL: test_tail_call_with_return +@@ -43,7 +43,7 @@ declare void @bar(...) + ; V9: save %sp + ; V9: call foo + ; V9-NEXT: nop +-; V9: jmp %i7+8 ++; V9: ret + ; V9-NEXT: restore %g0, %o0, %o0 + + define i32 @test_tail_call_with_return() nounwind { +Index: test/CodeGen/SPARC/leafproc.ll +=================================================================== +--- test/CodeGen/SPARC/leafproc.ll ++++ test/CodeGen/SPARC/leafproc.ll +@@ -1,7 +1,7 @@ + ; RUN: llc -march=sparc -disable-sparc-leaf-proc=0 < %s | FileCheck %s + + ; CHECK-LABEL: func_nobody: +-; CHECK: jmp %o7+8 ++; CHECK: retl + ; CHECK-NEXT: nop + define void @func_nobody() { + entry: +@@ -10,7 +10,7 @@ entry: + + + ; CHECK-LABEL: return_int_const: +-; CHECK: jmp %o7+8 ++; CHECK: retl + ; CHECK-NEXT: or %g0, 1729, %o0 + define i32 @return_int_const() { + entry: +@@ -19,7 +19,7 @@ entry: + + ; CHECK-LABEL: return_double_const: + ; CHECK: sethi +-; CHECK: jmp %o7+8 ++; CHECK: retl + ; CHECK-NEXT: ldd {{.*}}, %f0 + + define double @return_double_const() { +@@ -29,7 +29,7 @@ entry: + + ; CHECK-LABEL: leaf_proc_with_args: + ; CHECK: add {{%o[0-1]}}, {{%o[0-1]}}, [[R:%[go][0-7]]] +-; CHECK: jmp %o7+8 ++; CHECK: retl + ; CHECK-NEXT: add [[R]], %o2, %o0 + + define i32 @leaf_proc_with_args(i32 %a, i32 %b, i32 %c) { +@@ -42,7 +42,7 @@ entry: + ; CHECK-LABEL: leaf_proc_with_args_in_stack: + ; CHECK-DAG: ld [%sp+92], {{%[go][0-7]}} + ; CHECK-DAG: ld [%sp+96], {{%[go][0-7]}} +-; CHECK: jmp %o7+8 ++; CHECK: retl + ; CHECK-NEXT: add {{.*}}, %o0 + define i32 @leaf_proc_with_args_in_stack(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) { + entry: +@@ -63,7 +63,7 @@ entry: + ; CHECK: or %g0, 2, [[R2:%[go][0-7]]] + ; CHECK: st [[R2]], [%sp+100] + ; CHECK: ld {{.+}}, %o0 +-; CHECK: jmp %o7+8 ++; CHECK: retl + ; CHECK-NEXT: add %sp, 104, %sp + + define i32 @leaf_proc_with_local_array(i32 %a, i32 %b, i32 %c) { +Index: test/CodeGen/SPARC/fp128.ll +=================================================================== +--- test/CodeGen/SPARC/fp128.ll ++++ test/CodeGen/SPARC/fp128.ll +@@ -45,7 +45,7 @@ entry: + ; HARD: std %f{{.+}}, [%[[S1:.+]]] + ; HARD-DAG: ldd [%[[S0]]], %f{{.+}} + ; HARD-DAG: ldd [%[[S1]]], %f{{.+}} +-; HARD: jmp ++; HARD: jmp %o7+12 + + ; SOFT-LABEL: f128_spill + ; SOFT: std %f{{.+}}, [%[[S0:.+]]] +@@ -52,7 +52,7 @@ entry: + ; SOFT: std %f{{.+}}, [%[[S1:.+]]] + ; SOFT-DAG: ldd [%[[S0]]], %f{{.+}} + ; SOFT-DAG: ldd [%[[S1]]], %f{{.+}} +-; SOFT: jmp ++; SOFT: jmp %o7+12 + + define void @f128_spill(fp128* noalias sret %scalar.result, fp128* byval %a) { + entry: +@@ -132,13 +132,13 @@ entry: + ; HARD: ldub + ; HARD: faddq + ; HARD: stb +-; HARD: jmp ++; HARD: ret + + ; SOFT-LABEL: fp128_unaligned + ; SOFT: ldub + ; SOFT: call _Q_add + ; SOFT: stb +-; SOFT: jmp ++; SOFT: ret + + define void @fp128_unaligned(fp128* %a, fp128* %b, fp128* %c) { + entry: +Index: test/CodeGen/SPARC/2011-01-11-FrameAddr.ll +=================================================================== +--- test/CodeGen/SPARC/2011-01-11-FrameAddr.ll ++++ test/CodeGen/SPARC/2011-01-11-FrameAddr.ll +@@ -9,18 +9,18 @@ define i8* @frameaddr() nounwind readnone { + entry: + ;V8-LABEL: frameaddr: + ;V8: save %sp, -96, %sp +-;V8: jmp %i7+8 ++;V8: ret + ;V8: restore %g0, %fp, %o0 + + ;V9-LABEL: frameaddr: + ;V9: save %sp, -96, %sp +-;V9: jmp %i7+8 ++;V9: ret + ;V9: restore %g0, %fp, %o0 + + ;SPARC64-LABEL: frameaddr + ;SPARC64: save %sp, -128, %sp + ;SPARC64: add %fp, 2047, %i0 +-;SPARC64: jmp %i7+8 ++;SPARC64: ret + ;SPARC64: restore %g0, %g0, %g0 + + %0 = tail call i8* @llvm.frameaddress(i32 0) +Index: test/CodeGen/SPARC/constpool.ll +=================================================================== +--- test/CodeGen/SPARC/constpool.ll ++++ test/CodeGen/SPARC/constpool.ll +@@ -12,7 +12,7 @@ entry: + + ; abs32: floatCP + ; abs32: sethi %hi(.LCPI0_0), %[[R:[gilo][0-7]]] +-; abs32: jmp %o7+8 ++; abs32: retl + ; abs32: ld [%[[R]]+%lo(.LCPI0_0)], %f + + +@@ -20,7 +20,7 @@ entry: + ; abs44: sethi %h44(.LCPI0_0), %[[R1:[gilo][0-7]]] + ; abs44: add %[[R1]], %m44(.LCPI0_0), %[[R2:[gilo][0-7]]] + ; abs44: sllx %[[R2]], 12, %[[R3:[gilo][0-7]]] +-; abs44: jmp %o7+8 ++; abs44: retl + ; abs44: ld [%[[R3]]+%l44(.LCPI0_0)], %f1 + + +@@ -30,7 +30,7 @@ entry: + ; abs64: sethi %hh(.LCPI0_0), %[[R3:[gilo][0-7]]] + ; abs64: add %[[R3]], %hm(.LCPI0_0), %[[R4:[gilo][0-7]]] + ; abs64: sllx %[[R4]], 32, %[[R5:[gilo][0-7]]] +-; abs64: jmp %o7+8 ++; abs64: retl + ; abs64: ld [%[[R5]]+%[[R2]]], %f1 + + +@@ -40,7 +40,7 @@ entry: + ; v8pic32: add %[[R1]], %lo(.LCPI0_0), %[[Goffs:[gilo][0-7]]] + ; v8pic32: ld [%[[GOT:[gilo][0-7]]]+%[[Goffs]]], %[[Gaddr:[gilo][0-7]]] + ; v8pic32: ld [%[[Gaddr]]], %f0 +-; v8pic32: jmp %i7+8 ++; v8pic32: ret + ; v8pic32: restore + + +@@ -51,7 +51,7 @@ entry: + ; v9pic32: add %[[R1]], %lo(.LCPI0_0), %[[Goffs:[gilo][0-7]]] + ; v9pic32: ldx [%[[GOT:[gilo][0-7]]]+%[[Goffs]]], %[[Gaddr:[gilo][0-7]]] + ; v9pic32: ld [%[[Gaddr]]], %f1 +-; v9pic32: jmp %i7+8 ++; v9pic32: ret + ; v9pic32: restore + + +Index: test/CodeGen/SPARC/globals.ll +=================================================================== +--- test/CodeGen/SPARC/globals.ll ++++ test/CodeGen/SPARC/globals.ll +@@ -14,7 +14,7 @@ define zeroext i8 @loadG() { + + ; abs32: loadG + ; abs32: sethi %hi(G), %[[R:[gilo][0-7]]] +-; abs32: jmp %o7+8 ++; abs32: retl + ; abs32: ldub [%[[R]]+%lo(G)], %o0 + + +@@ -22,7 +22,7 @@ define zeroext i8 @loadG() { + ; abs44: sethi %h44(G), %[[R1:[gilo][0-7]]] + ; abs44: add %[[R1]], %m44(G), %[[R2:[gilo][0-7]]] + ; abs44: sllx %[[R2]], 12, %[[R3:[gilo][0-7]]] +-; abs44: jmp %o7+8 ++; abs44: retl + ; abs44: ldub [%[[R3]]+%l44(G)], %o0 + + +@@ -32,7 +32,7 @@ define zeroext i8 @loadG() { + ; abs64: sethi %hh(G), %[[R3:[gilo][0-7]]] + ; abs64: add %[[R3]], %hm(G), %[[R4:[gilo][0-7]]] + ; abs64: sllx %[[R4]], 32, %[[R5:[gilo][0-7]]] +-; abs64: jmp %o7+8 ++; abs64: retl + ; abs64: ldub [%[[R5]]+%[[R2]]], %o0 + + +@@ -42,7 +42,7 @@ define zeroext i8 @loadG() { + ; v8pic32: add %[[R1]], %lo(G), %[[Goffs:[gilo][0-7]]] + ; v8pic32: ld [%[[GOT:[gilo][0-7]]]+%[[Goffs]]], %[[Gaddr:[gilo][0-7]]] + ; v8pic32: ldub [%[[Gaddr]]], %i0 +-; v8pic32: jmp %i7+8 ++; v8pic32: ret + ; v8pic32: restore + + +@@ -52,6 +52,6 @@ define zeroext i8 @loadG() { + ; v9pic32: add %[[R1]], %lo(G), %[[Goffs:[gilo][0-7]]] + ; v9pic32: ldx [%[[GOT:[gilo][0-7]]]+%[[Goffs]]], %[[Gaddr:[gilo][0-7]]] + ; v9pic32: ldub [%[[Gaddr]]], %i0 +-; v9pic32: jmp %i7+8 ++; v9pic32: ret + ; v9pic32: restore + +Index: test/CodeGen/SPARC/rem.ll +=================================================================== +--- test/CodeGen/SPARC/rem.ll ++++ test/CodeGen/SPARC/rem.ll +@@ -3,7 +3,7 @@ + ; CHECK-LABEL: test1: + ; CHECK: sdivx %o0, %o1, %o2 + ; CHECK-NEXT: mulx %o2, %o1, %o1 +-; CHECK-NEXT: jmp %o7+8 ++; CHECK-NEXT: retl + ; CHECK-NEXT: sub %o0, %o1, %o0 + + define i64 @test1(i64 %X, i64 %Y) { +@@ -14,7 +14,7 @@ define i64 @test1(i64 %X, i64 %Y) { + ; CHECK-LABEL: test2: + ; CHECK: udivx %o0, %o1, %o2 + ; CHECK-NEXT: mulx %o2, %o1, %o1 +-; CHECK-NEXT: jmp %o7+8 ++; CHECK-NEXT: retl + ; CHECK-NEXT: sub %o0, %o1, %o0 + + define i64 @test2(i64 %X, i64 %Y) { +Index: test/CodeGen/SPARC/2011-01-19-DelaySlot.ll +=================================================================== +--- test/CodeGen/SPARC/2011-01-19-DelaySlot.ll ++++ test/CodeGen/SPARC/2011-01-19-DelaySlot.ll +@@ -7,7 +7,7 @@ entry: + ; CHECK: test + ; CHECK: call bar + ; CHECK-NOT: nop +-; CHECK: jmp ++; CHECK: ret + ; CHECK-NEXT: restore + %0 = tail call i32 @bar(i32 %a) nounwind + ret i32 %0 +@@ -18,7 +18,7 @@ entry: + ; CHECK: test_jmpl + ; CHECK: call + ; CHECK-NOT: nop +-; CHECK: jmp ++; CHECK: ret + ; CHECK-NEXT: restore + %0 = tail call i32 %f(i32 %a, i32 %b) nounwind + ret i32 %0 +@@ -47,7 +47,7 @@ bb: + + bb5: ; preds = %bb, %entry + %a_addr.1.lcssa = phi i32 [ %a, %entry ], [ %a_addr.0, %bb ] +-;CHECK: jmp ++;CHECK: retl + ;CHECK-NOT: restore + ret i32 %a_addr.1.lcssa + } +@@ -110,7 +110,7 @@ declare i32 @func(i32*) + define i32 @restore_add(i32 %a, i32 %b) { + entry: + ;CHECK-LABEL: restore_add: +-;CHECK: jmp %i7+8 ++;CHECK: ret + ;CHECK: restore %o0, %i1, %o0 + %0 = tail call i32 @bar(i32 %a) nounwind + %1 = add nsw i32 %0, %b +@@ -120,7 +120,7 @@ entry: + define i32 @restore_add_imm(i32 %a) { + entry: + ;CHECK-LABEL: restore_add_imm: +-;CHECK: jmp %i7+8 ++;CHECK: ret + ;CHECK: restore %o0, 20, %o0 + %0 = tail call i32 @bar(i32 %a) nounwind + %1 = add nsw i32 %0, 20 +@@ -130,7 +130,7 @@ entry: + define i32 @restore_or(i32 %a) { + entry: + ;CHECK-LABEL: restore_or: +-;CHECK: jmp %i7+8 ++;CHECK: ret + ;CHECK: restore %g0, %o0, %o0 + %0 = tail call i32 @bar(i32 %a) nounwind + ret i32 %0 +@@ -140,7 +140,7 @@ define i32 @restore_or_imm(i32 %a) { + entry: + ;CHECK-LABEL: restore_or_imm: + ;CHECK: or %o0, 20, %i0 +-;CHECK: jmp %i7+8 ++;CHECK: ret + ;CHECK: restore %g0, %g0, %g0 + %0 = tail call i32 @bar(i32 %a) nounwind + %1 = or i32 %0, 20 +Index: test/CodeGen/SPARC/64bit.ll +=================================================================== +--- test/CodeGen/SPARC/64bit.ll ++++ test/CodeGen/SPARC/64bit.ll +@@ -5,7 +5,7 @@ + ; CHECK: or %g0, %i1, %i0 + + ; OPT-LABEL: ret2: +-; OPT: jmp %o7+8 ++; OPT: retl + ; OPT: or %g0, %o1, %o0 + define i64 @ret2(i64 %a, i64 %b) { + ret i64 %b +@@ -15,7 +15,7 @@ define i64 @ret2(i64 %a, i64 %b) { + ; CHECK: sllx %i0, 7, %i0 + + ; OPT-LABEL: shl_imm: +-; OPT: jmp %o7+8 ++; OPT: retl + ; OPT: sllx %o0, 7, %o0 + define i64 @shl_imm(i64 %a) { + %x = shl i64 %a, 7 +@@ -26,7 +26,7 @@ define i64 @shl_imm(i64 %a) { + ; CHECK: srax %i0, %i1, %i0 + + ; OPT-LABEL: sra_reg: +-; OPT: jmp %o7+8 ++; OPT: retl + ; OPT: srax %o0, %o1, %o0 + define i64 @sra_reg(i64 %a, i64 %b) { + %x = ashr i64 %a, %b +@@ -42,7 +42,7 @@ define i64 @sra_reg(i64 %a, i64 %b) { + ; CHECK: or %g0, 0, %i0 + + ; OPT: ret_imm0 +-; OPT: jmp %o7+8 ++; OPT: retl + ; OPT: or %g0, 0, %o0 + define i64 @ret_imm0() { + ret i64 0 +@@ -52,7 +52,7 @@ define i64 @ret_imm0() { + ; CHECK: or %g0, -4096, %i0 + + ; OPT: ret_simm13 +-; OPT: jmp %o7+8 ++; OPT: retl + ; OPT: or %g0, -4096, %o0 + define i64 @ret_simm13() { + ret i64 -4096 +@@ -64,7 +64,7 @@ define i64 @ret_simm13() { + ; CHECK: restore + + ; OPT: ret_sethi +-; OPT: jmp %o7+8 ++; OPT: retl + ; OPT: sethi 4, %o0 + define i64 @ret_sethi() { + ret i64 4096 +@@ -76,7 +76,7 @@ define i64 @ret_sethi() { + + ; OPT: ret_sethi_or + ; OPT: sethi 4, [[R:%[go][0-7]]] +-; OPT: jmp %o7+8 ++; OPT: retl + ; OPT: or [[R]], 1, %o0 + + define i64 @ret_sethi_or() { +@@ -89,7 +89,7 @@ define i64 @ret_sethi_or() { + + ; OPT: ret_nimm33 + ; OPT: sethi 4, [[R:%[go][0-7]]] +-; OPT: jmp %o7+8 ++; OPT: retl + ; OPT: xor [[R]], -4, %o0 + + define i64 @ret_nimm33() { +Index: lib/Target/Sparc/SparcInstrAliases.td +=================================================================== +--- lib/Target/Sparc/SparcInstrAliases.td ++++ lib/Target/Sparc/SparcInstrAliases.td +@@ -128,3 +128,9 @@ def : InstAlias<"jmp $addr", (JMPLri G0, MEMri:$ad + // call addr -> jmpl addr, %o7 + def : InstAlias<"call $addr", (JMPLrr O7, MEMrr:$addr)>; + def : InstAlias<"call $addr", (JMPLri O7, MEMri:$addr)>; ++ ++// retl -> RETL 8 ++def : InstAlias<"retl", (RETL 8)>; ++ ++// ret -> RET 8 ++def : InstAlias<"ret", (RET 8)>; diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199014-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199014-sparc.diff new file mode 100644 index 0000000..6db27a06 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199014-sparc.diff @@ -0,0 +1,133 @@ +Pull in r199014 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Bundle instruction with delay slow and its filler. Now, we can use -verify-machineinstrs with SPARC backend. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/DelaySlotFiller.cpp +=================================================================== +--- lib/Target/Sparc/DelaySlotFiller.cpp ++++ lib/Target/Sparc/DelaySlotFiller.cpp +@@ -19,6 +19,7 @@ + #include "llvm/ADT/Statistic.h" + #include "llvm/CodeGen/MachineFunctionPass.h" + #include "llvm/CodeGen/MachineInstrBuilder.h" ++#include "llvm/CodeGen/MachineRegisterInfo.h" + #include "llvm/Support/CommandLine.h" + #include "llvm/Target/TargetInstrInfo.h" + #include "llvm/Target/TargetMachine.h" +@@ -55,6 +56,11 @@ namespace { + bool runOnMachineBasicBlock(MachineBasicBlock &MBB); + bool runOnMachineFunction(MachineFunction &F) { + bool Changed = false; ++ ++ // This pass invalidates liveness information when it reorders ++ // instructions to fill delay slot. ++ F.getRegInfo().invalidateLiveness(); ++ + for (MachineFunction::iterator FI = F.begin(), FE = F.end(); + FI != FE; ++FI) + Changed |= runOnMachineBasicBlock(*FI); +@@ -61,9 +67,6 @@ namespace { + return Changed; + } + +- bool isDelayFiller(MachineBasicBlock &MBB, +- MachineBasicBlock::iterator candidate); +- + void insertCallDefsUses(MachineBasicBlock::iterator MI, + SmallSet<unsigned, 32>& RegDefs, + SmallSet<unsigned, 32>& RegUses); +@@ -152,6 +155,10 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBl + assert (J != MBB.end() && "MI needs a delay instruction."); + BuildMI(MBB, ++J, MI->getDebugLoc(), + TII->get(SP::UNIMP)).addImm(structSize); ++ // Bundle the delay filler and unimp with the instruction. ++ MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), J); ++ } else { ++ MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), I); + } + } + return Changed; +@@ -209,7 +216,7 @@ Filler::findDelayInstr(MachineBasicBlock &MBB, + || I->isInlineAsm() + || I->isLabel() + || I->hasDelaySlot() +- || isDelayFiller(MBB, I)) ++ || I->isBundledWithSucc()) + break; + + if (delayHasHazard(I, sawLoad, sawStore, RegDefs, RegUses)) { +@@ -332,18 +339,6 @@ bool Filler::IsRegInSet(SmallSet<unsigned, 32>& Re + return false; + } + +-// return true if the candidate is a delay filler. +-bool Filler::isDelayFiller(MachineBasicBlock &MBB, +- MachineBasicBlock::iterator candidate) +-{ +- if (candidate == MBB.begin()) +- return false; +- if (candidate->getOpcode() == SP::UNIMP) +- return true; +- --candidate; +- return candidate->hasDelaySlot(); +-} +- + bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize) + { + if (!I->isCall()) +@@ -484,10 +479,10 @@ bool Filler::tryCombineRestoreWithPrevInst(Machine + && MBBI->getOperand(1).getReg() == SP::G0 + && MBBI->getOperand(2).getReg() == SP::G0); + +- MachineBasicBlock::iterator PrevInst = MBBI; --PrevInst; ++ MachineBasicBlock::iterator PrevInst = llvm::prior(MBBI); + +- // It cannot combine with a delay filler. +- if (isDelayFiller(MBB, PrevInst)) ++ // It cannot be combined with a bundled instruction. ++ if (PrevInst->isBundledWithSucc()) + return false; + + const TargetInstrInfo *TII = TM.getInstrInfo(); +Index: lib/Target/Sparc/SparcAsmPrinter.cpp +=================================================================== +--- lib/Target/Sparc/SparcAsmPrinter.cpp ++++ lib/Target/Sparc/SparcAsmPrinter.cpp +@@ -184,7 +184,6 @@ static void LowerGETPCXAndEmitMCInsts(const Machin + + void SparcAsmPrinter::EmitInstruction(const MachineInstr *MI) + { +- MCInst TmpInst; + + switch (MI->getOpcode()) { + default: break; +@@ -195,8 +194,13 @@ void SparcAsmPrinter::EmitInstruction(const Machin + LowerGETPCXAndEmitMCInsts(MI, OutStreamer, OutContext); + return; + } +- LowerSparcMachineInstrToMCInst(MI, TmpInst, *this); +- OutStreamer.EmitInstruction(TmpInst); ++ MachineBasicBlock::const_instr_iterator I = MI; ++ MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); ++ do { ++ MCInst TmpInst; ++ LowerSparcMachineInstrToMCInst(I, TmpInst, *this); ++ OutStreamer.EmitInstruction(TmpInst); ++ } while ((++I != E) && I->isInsideBundle()); // Delay slot check. + } + + void SparcAsmPrinter::EmitFunctionBodyStart() { +Index: test/CodeGen/SPARC/2011-01-19-DelaySlot.ll +=================================================================== +--- test/CodeGen/SPARC/2011-01-19-DelaySlot.ll ++++ test/CodeGen/SPARC/2011-01-19-DelaySlot.ll +@@ -1,5 +1,5 @@ +-;RUN: llc -march=sparc < %s | FileCheck %s +-;RUN: llc -march=sparc -O0 < %s | FileCheck %s -check-prefix=UNOPT ++;RUN: llc -march=sparc < %s -verify-machineinstrs | FileCheck %s ++;RUN: llc -march=sparc -O0 < %s -verify-machineinstrs | FileCheck %s -check-prefix=UNOPT + + + define i32 @test(i32 %a) nounwind { diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199024-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199024-sparc.diff new file mode 100644 index 0000000..35bfc2b --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199024-sparc.diff @@ -0,0 +1,69 @@ +Pull in r199024 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add missing processor types: v7 and niagara + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/Sparc.td +=================================================================== +--- lib/Target/Sparc/Sparc.td ++++ lib/Target/Sparc/Sparc.td +@@ -56,6 +56,7 @@ class Proc<string Name, list<SubtargetFeature> Fea + : Processor<Name, NoItineraries, Features>; + + def : Proc<"generic", []>; ++def : Proc<"v7", []>; + def : Proc<"v8", []>; + def : Proc<"supersparc", []>; + def : Proc<"sparclite", []>; +@@ -67,7 +68,10 @@ def : Proc<"tsc701", []>; + def : Proc<"v9", [FeatureV9]>; + def : Proc<"ultrasparc", [FeatureV9, FeatureV8Deprecated]>; + def : Proc<"ultrasparc3", [FeatureV9, FeatureV8Deprecated]>; +-def : Proc<"ultrasparc3-vis", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>; ++def : Proc<"niagara", [FeatureV9, FeatureV8Deprecated]>; ++def : Proc<"niagara2", [FeatureV9, FeatureV8Deprecated]>; ++def : Proc<"niagara3", [FeatureV9, FeatureV8Deprecated]>; ++def : Proc<"niagara4", [FeatureV9, FeatureV8Deprecated]>; + + def SparcAsmWriter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; +Index: lib/Target/Sparc/SparcSubtarget.cpp +=================================================================== +--- lib/Target/Sparc/SparcSubtarget.cpp ++++ lib/Target/Sparc/SparcSubtarget.cpp +@@ -35,13 +35,8 @@ SparcSubtarget::SparcSubtarget(const std::string & + + // Determine default and user specified characteristics + std::string CPUName = CPU; +- if (CPUName.empty()) { +- if (is64Bit) +- CPUName = "v9"; +- else +- CPUName = "v8"; +- } +- IsV9 = CPUName == "v9"; ++ if (CPUName.empty()) ++ CPUName = (is64Bit) ? "v9" : "v8"; + + // Parse features string. + ParseSubtargetFeatures(CPUName, FS); +Index: test/CodeGen/SPARC/ctpop.ll +=================================================================== +--- test/CodeGen/SPARC/ctpop.ll ++++ test/CodeGen/SPARC/ctpop.ll +@@ -1,6 +1,13 @@ + ; RUN: llc < %s -march=sparc -mattr=-v9 | FileCheck %s -check-prefix=V8 + ; RUN: llc < %s -march=sparc -mattr=+v9 | FileCheck %s -check-prefix=V9 +-; RUN: llc < %s -march=sparcv9 | FileCheck %s -check-prefix=SPARC64 ++; RUN: llc < %s -march=sparc -mcpu=v9 | FileCheck %s -check-prefix=V9 ++; RUN: llc < %s -march=sparc -mcpu=ultrasparc | FileCheck %s -check-prefix=V9 ++; RUN: llc < %s -march=sparc -mcpu=ultrasparc3 | FileCheck %s -check-prefix=V9 ++; RUN: llc < %s -march=sparc -mcpu=niagara | FileCheck %s -check-prefix=V9 ++; RUN: llc < %s -march=sparc -mcpu=niagara2 | FileCheck %s -check-prefix=V9 ++; RUN: llc < %s -march=sparc -mcpu=niagara3 | FileCheck %s -check-prefix=V9 ++; RUN: llc < %s -march=sparc -mcpu=niagara4 | FileCheck %s -check-prefix=V9 ++; RUN: llc < %s -march=sparcv9 | FileCheck %s -check-prefix=SPARC64 + + declare i32 @llvm.ctpop.i32(i32) + diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199028-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199028-sparc.diff new file mode 100644 index 0000000..78bcc61 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199028-sparc.diff @@ -0,0 +1,147 @@ +Pull in r199028 from upstream llvm trunk (by Jakob Stoklund Olesen): + + The SPARCv9 ABI returns a float in %f0. + + This is different from the argument passing convention which puts the + first float argument in %f1. + + With this patch, all returned floats are treated as if the 'inreg' flag + were set. This means multiple float return values get packed in %f0, + %f1, %f2, ... + + Note that when returning a struct in registers, clang will set the + 'inreg' flag on the return value, so that behavior is unchanged. This + also happens when returning a float _Complex. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/CodeGen/SPARC/64abi.ll +=================================================================== +--- test/CodeGen/SPARC/64abi.ll ++++ test/CodeGen/SPARC/64abi.ll +@@ -180,7 +180,7 @@ define void @call_inreg_fi(i32* %p, i32 %i1, float + } + + ; CHECK: inreg_ff +-; CHECK: fsubs %f0, %f1, %f1 ++; CHECK: fsubs %f0, %f1, %f0 + define float @inreg_ff(float inreg %a0, ; %f0 + float inreg %a1) { ; %f1 + %rv = fsub float %a0, %a1 +@@ -262,10 +262,10 @@ define void @call_ret_i64_pair(i64* %i0) { + ret void + } + +-; This is not a C struct, each member uses 8 bytes. ++; This is not a C struct, the i32 member uses 8 bytes, but the float only 4. + ; CHECK: ret_i32_float_pair + ; CHECK: ld [%i2], %i0 +-; CHECK: ld [%i3], %f3 ++; CHECK: ld [%i3], %f2 + define { i32, float } @ret_i32_float_pair(i32 %a0, i32 %a1, + i32* %p, float* %q) { + %r1 = load i32* %p +@@ -279,7 +279,7 @@ define { i32, float } @ret_i32_float_pair(i32 %a0, + ; CHECK: call_ret_i32_float_pair + ; CHECK: call ret_i32_float_pair + ; CHECK: st %o0, [%i0] +-; CHECK: st %f3, [%i1] ++; CHECK: st %f2, [%i1] + define void @call_ret_i32_float_pair(i32* %i0, float* %i1) { + %rv = call { i32, float } @ret_i32_float_pair(i32 undef, i32 undef, + i32* undef, float* undef) +Index: test/CodeGen/SPARC/constpool.ll +=================================================================== +--- test/CodeGen/SPARC/constpool.ll ++++ test/CodeGen/SPARC/constpool.ll +@@ -21,7 +21,7 @@ entry: + ; abs44: add %[[R1]], %m44(.LCPI0_0), %[[R2:[gilo][0-7]]] + ; abs44: sllx %[[R2]], 12, %[[R3:[gilo][0-7]]] + ; abs44: retl +-; abs44: ld [%[[R3]]+%l44(.LCPI0_0)], %f1 ++; abs44: ld [%[[R3]]+%l44(.LCPI0_0)], %f0 + + + ; abs64: floatCP +@@ -31,7 +31,7 @@ entry: + ; abs64: add %[[R3]], %hm(.LCPI0_0), %[[R4:[gilo][0-7]]] + ; abs64: sllx %[[R4]], 32, %[[R5:[gilo][0-7]]] + ; abs64: retl +-; abs64: ld [%[[R5]]+%[[R2]]], %f1 ++; abs64: ld [%[[R5]]+%[[R2]]], %f0 + + + ; v8pic32: floatCP +@@ -50,7 +50,7 @@ entry: + ; v9pic32: sethi %hi(.LCPI0_0), %[[R1:[gilo][0-7]]] + ; v9pic32: add %[[R1]], %lo(.LCPI0_0), %[[Goffs:[gilo][0-7]]] + ; v9pic32: ldx [%[[GOT:[gilo][0-7]]]+%[[Goffs]]], %[[Gaddr:[gilo][0-7]]] +-; v9pic32: ld [%[[Gaddr]]], %f1 ++; v9pic32: ld [%[[Gaddr]]], %f0 + ; v9pic32: ret + ; v9pic32: restore + +Index: test/CodeGen/SPARC/64cond.ll +=================================================================== +--- test/CodeGen/SPARC/64cond.ll ++++ test/CodeGen/SPARC/64cond.ll +@@ -80,7 +80,7 @@ entry: + ; CHECK: selectf32_xcc + ; CHECK: cmp %i0, %i1 + ; CHECK: fmovsg %xcc, %f5, %f7 +-; CHECK: fmovs %f7, %f1 ++; CHECK: fmovs %f7, %f0 + define float @selectf32_xcc(i64 %x, i64 %y, float %a, float %b) { + entry: + %tobool = icmp sgt i64 %x, %y +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -254,7 +254,7 @@ SparcTargetLowering::LowerReturn_64(SDValue Chain, + DAG.getTarget(), RVLocs, *DAG.getContext()); + + // Analyze return values. +- CCInfo.AnalyzeReturn(Outs, CC_Sparc64); ++ CCInfo.AnalyzeReturn(Outs, RetCC_Sparc64); + + SDValue Flag; + SmallVector<SDValue, 4> RetOps(1, Chain); +@@ -1258,7 +1258,7 @@ SparcTargetLowering::LowerCall_64(TargetLowering:: + if (CLI.Ins.size() == 1 && CLI.Ins[0].VT == MVT::f32 && CLI.CS == 0) + CLI.Ins[0].Flags.setInReg(); + +- RVInfo.AnalyzeCallResult(CLI.Ins, CC_Sparc64); ++ RVInfo.AnalyzeCallResult(CLI.Ins, RetCC_Sparc64); + + // Copy all of the result registers out of their specified physreg. + for (unsigned i = 0; i != RVLocs.size(); ++i) { +Index: lib/Target/Sparc/SparcCallingConv.td +=================================================================== +--- lib/Target/Sparc/SparcCallingConv.td ++++ lib/Target/Sparc/SparcCallingConv.td +@@ -103,7 +103,7 @@ def RetCC_Sparc32 : CallingConv<[ + // Function return values are passed exactly like function arguments, except a + // struct up to 32 bytes in size can be returned in registers. + +-// Function arguments AND return values. ++// Function arguments AND most return values. + def CC_Sparc64 : CallingConv<[ + // The frontend uses the inreg flag to indicate i32 and float arguments from + // structs. These arguments are not promoted to 64 bits, but they can still +@@ -118,6 +118,15 @@ def CC_Sparc64 : CallingConv<[ + CCCustom<"CC_Sparc64_Full"> + ]>; + ++def RetCC_Sparc64 : CallingConv<[ ++ // A single f32 return value always goes in %f0. The ABI doesn't specify what ++ // happens to multiple f32 return values outside a struct. ++ CCIfType<[f32], CCCustom<"CC_Sparc64_Half">>, ++ ++ // Otherwise, return values are passed exactly like arguments. ++ CCDelegateTo<CC_Sparc64> ++]>; ++ + // Callee-saved registers are handled by the register window mechanism. + def CSR : CalleeSavedRegs<(add)> { + let OtherPreserved = (add (sequence "I%u", 0, 7), diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199031-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199031-sparc.diff new file mode 100644 index 0000000..5eb9549 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199031-sparc.diff @@ -0,0 +1,42 @@ +Pull in r199031 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Replace (unsigned)-1 with ~OU as suggested by Reid Kleckner. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/Disassembler/SparcDisassembler.cpp +=================================================================== +--- lib/Target/Sparc/Disassembler/SparcDisassembler.cpp ++++ lib/Target/Sparc/Disassembler/SparcDisassembler.cpp +@@ -104,14 +104,14 @@ static const unsigned DFPRegDecoderTable[] = { + SP::D14, SP::D30, SP::D15, SP::D31 }; + + static const unsigned QFPRegDecoderTable[] = { +- SP::Q0, SP::Q8, (unsigned)-1, (unsigned)-1, +- SP::Q1, SP::Q9, (unsigned)-1, (unsigned)-1, +- SP::Q2, SP::Q10, (unsigned)-1, (unsigned)-1, +- SP::Q3, SP::Q11, (unsigned)-1, (unsigned)-1, +- SP::Q4, SP::Q12, (unsigned)-1, (unsigned)-1, +- SP::Q5, SP::Q13, (unsigned)-1, (unsigned)-1, +- SP::Q6, SP::Q14, (unsigned)-1, (unsigned)-1, +- SP::Q7, SP::Q15, (unsigned)-1, (unsigned)-1 } ; ++ SP::Q0, SP::Q8, ~0U, ~0U, ++ SP::Q1, SP::Q9, ~0U, ~0U, ++ SP::Q2, SP::Q10, ~0U, ~0U, ++ SP::Q3, SP::Q11, ~0U, ~0U, ++ SP::Q4, SP::Q12, ~0U, ~0U, ++ SP::Q5, SP::Q13, ~0U, ~0U, ++ SP::Q6, SP::Q14, ~0U, ~0U, ++ SP::Q7, SP::Q15, ~0U, ~0U } ; + + static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst, + unsigned RegNo, +@@ -168,7 +168,7 @@ static DecodeStatus DecodeQFPRegsRegisterClass(MCI + return MCDisassembler::Fail; + + unsigned Reg = QFPRegDecoderTable[RegNo]; +- if (Reg == (unsigned)-1) ++ if (Reg == ~0U) + return MCDisassembler::Fail; + Inst.addOperand(MCOperand::CreateReg(Reg)); + return MCDisassembler::Success; diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199033-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199033-sparc.diff new file mode 100644 index 0000000..c4b3438 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199033-sparc.diff @@ -0,0 +1,944 @@ +Pull in r199033 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add support for parsing floating point instructions. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -601,91 +601,91 @@ let Defs = [Y], rd = 0 in { + } + // Convert Integer to Floating-point Instructions, p. 141 + def FITOS : F3_3u<2, 0b110100, 0b011000100, +- (outs FPRegs:$dst), (ins FPRegs:$src), +- "fitos $src, $dst", +- [(set FPRegs:$dst, (SPitof FPRegs:$src))]>; ++ (outs FPRegs:$rd), (ins FPRegs:$rs2), ++ "fitos $rs2, $rd", ++ [(set FPRegs:$rd, (SPitof FPRegs:$rs2))]>; + def FITOD : F3_3u<2, 0b110100, 0b011001000, +- (outs DFPRegs:$dst), (ins FPRegs:$src), +- "fitod $src, $dst", +- [(set DFPRegs:$dst, (SPitof FPRegs:$src))]>; ++ (outs DFPRegs:$rd), (ins FPRegs:$rs2), ++ "fitod $rs2, $rd", ++ [(set DFPRegs:$rd, (SPitof FPRegs:$rs2))]>; + def FITOQ : F3_3u<2, 0b110100, 0b011001100, +- (outs QFPRegs:$dst), (ins FPRegs:$src), +- "fitoq $src, $dst", +- [(set QFPRegs:$dst, (SPitof FPRegs:$src))]>, ++ (outs QFPRegs:$rd), (ins FPRegs:$rs2), ++ "fitoq $rs2, $rd", ++ [(set QFPRegs:$rd, (SPitof FPRegs:$rs2))]>, + Requires<[HasHardQuad]>; + + // Convert Floating-point to Integer Instructions, p. 142 + def FSTOI : F3_3u<2, 0b110100, 0b011010001, +- (outs FPRegs:$dst), (ins FPRegs:$src), +- "fstoi $src, $dst", +- [(set FPRegs:$dst, (SPftoi FPRegs:$src))]>; ++ (outs FPRegs:$rd), (ins FPRegs:$rs2), ++ "fstoi $rs2, $rd", ++ [(set FPRegs:$rd, (SPftoi FPRegs:$rs2))]>; + def FDTOI : F3_3u<2, 0b110100, 0b011010010, +- (outs FPRegs:$dst), (ins DFPRegs:$src), +- "fdtoi $src, $dst", +- [(set FPRegs:$dst, (SPftoi DFPRegs:$src))]>; ++ (outs FPRegs:$rd), (ins DFPRegs:$rs2), ++ "fdtoi $rs2, $rd", ++ [(set FPRegs:$rd, (SPftoi DFPRegs:$rs2))]>; + def FQTOI : F3_3u<2, 0b110100, 0b011010011, +- (outs FPRegs:$dst), (ins QFPRegs:$src), +- "fqtoi $src, $dst", +- [(set FPRegs:$dst, (SPftoi QFPRegs:$src))]>, ++ (outs FPRegs:$rd), (ins QFPRegs:$rs2), ++ "fqtoi $rs2, $rd", ++ [(set FPRegs:$rd, (SPftoi QFPRegs:$rs2))]>, + Requires<[HasHardQuad]>; + + // Convert between Floating-point Formats Instructions, p. 143 + def FSTOD : F3_3u<2, 0b110100, 0b011001001, +- (outs DFPRegs:$dst), (ins FPRegs:$src), +- "fstod $src, $dst", +- [(set f64:$dst, (fextend f32:$src))]>; ++ (outs DFPRegs:$rd), (ins FPRegs:$rs2), ++ "fstod $rs2, $rd", ++ [(set f64:$rd, (fextend f32:$rs2))]>; + def FSTOQ : F3_3u<2, 0b110100, 0b011001101, +- (outs QFPRegs:$dst), (ins FPRegs:$src), +- "fstoq $src, $dst", +- [(set f128:$dst, (fextend f32:$src))]>, ++ (outs QFPRegs:$rd), (ins FPRegs:$rs2), ++ "fstoq $rs2, $rd", ++ [(set f128:$rd, (fextend f32:$rs2))]>, + Requires<[HasHardQuad]>; + def FDTOS : F3_3u<2, 0b110100, 0b011000110, +- (outs FPRegs:$dst), (ins DFPRegs:$src), +- "fdtos $src, $dst", +- [(set f32:$dst, (fround f64:$src))]>; +-def FDTOQ : F3_3u<2, 0b110100, 0b01101110, +- (outs QFPRegs:$dst), (ins DFPRegs:$src), +- "fdtoq $src, $dst", +- [(set f128:$dst, (fextend f64:$src))]>, ++ (outs FPRegs:$rd), (ins DFPRegs:$rs2), ++ "fdtos $rs2, $rd", ++ [(set f32:$rd, (fround f64:$rs2))]>; ++def FDTOQ : F3_3u<2, 0b110100, 0b011001110, ++ (outs QFPRegs:$rd), (ins DFPRegs:$rs2), ++ "fdtoq $rs2, $rd", ++ [(set f128:$rd, (fextend f64:$rs2))]>, + Requires<[HasHardQuad]>; + def FQTOS : F3_3u<2, 0b110100, 0b011000111, +- (outs FPRegs:$dst), (ins QFPRegs:$src), +- "fqtos $src, $dst", +- [(set f32:$dst, (fround f128:$src))]>, ++ (outs FPRegs:$rd), (ins QFPRegs:$rs2), ++ "fqtos $rs2, $rd", ++ [(set f32:$rd, (fround f128:$rs2))]>, + Requires<[HasHardQuad]>; + def FQTOD : F3_3u<2, 0b110100, 0b011001011, +- (outs DFPRegs:$dst), (ins QFPRegs:$src), +- "fqtod $src, $dst", +- [(set f64:$dst, (fround f128:$src))]>, ++ (outs DFPRegs:$rd), (ins QFPRegs:$rs2), ++ "fqtod $rs2, $rd", ++ [(set f64:$rd, (fround f128:$rs2))]>, + Requires<[HasHardQuad]>; + + // Floating-point Move Instructions, p. 144 + def FMOVS : F3_3u<2, 0b110100, 0b000000001, +- (outs FPRegs:$dst), (ins FPRegs:$src), +- "fmovs $src, $dst", []>; ++ (outs FPRegs:$rd), (ins FPRegs:$rs2), ++ "fmovs $rs2, $rd", []>; + def FNEGS : F3_3u<2, 0b110100, 0b000000101, +- (outs FPRegs:$dst), (ins FPRegs:$src), +- "fnegs $src, $dst", +- [(set f32:$dst, (fneg f32:$src))]>; ++ (outs FPRegs:$rd), (ins FPRegs:$rs2), ++ "fnegs $rs2, $rd", ++ [(set f32:$rd, (fneg f32:$rs2))]>; + def FABSS : F3_3u<2, 0b110100, 0b000001001, +- (outs FPRegs:$dst), (ins FPRegs:$src), +- "fabss $src, $dst", +- [(set f32:$dst, (fabs f32:$src))]>; ++ (outs FPRegs:$rd), (ins FPRegs:$rs2), ++ "fabss $rs2, $rd", ++ [(set f32:$rd, (fabs f32:$rs2))]>; + + + // Floating-point Square Root Instructions, p.145 + def FSQRTS : F3_3u<2, 0b110100, 0b000101001, +- (outs FPRegs:$dst), (ins FPRegs:$src), +- "fsqrts $src, $dst", +- [(set f32:$dst, (fsqrt f32:$src))]>; ++ (outs FPRegs:$rd), (ins FPRegs:$rs2), ++ "fsqrts $rs2, $rd", ++ [(set f32:$rd, (fsqrt f32:$rs2))]>; + def FSQRTD : F3_3u<2, 0b110100, 0b000101010, +- (outs DFPRegs:$dst), (ins DFPRegs:$src), +- "fsqrtd $src, $dst", +- [(set f64:$dst, (fsqrt f64:$src))]>; ++ (outs DFPRegs:$rd), (ins DFPRegs:$rs2), ++ "fsqrtd $rs2, $rd", ++ [(set f64:$rd, (fsqrt f64:$rs2))]>; + def FSQRTQ : F3_3u<2, 0b110100, 0b000101011, +- (outs QFPRegs:$dst), (ins QFPRegs:$src), +- "fsqrtq $src, $dst", +- [(set f128:$dst, (fsqrt f128:$src))]>, ++ (outs QFPRegs:$rd), (ins QFPRegs:$rs2), ++ "fsqrtq $rs2, $rd", ++ [(set f128:$rd, (fsqrt f128:$rs2))]>, + Requires<[HasHardQuad]>; + + +@@ -692,73 +692,73 @@ def FSQRTQ : F3_3u<2, 0b110100, 0b000101011, + + // Floating-point Add and Subtract Instructions, p. 146 + def FADDS : F3_3<2, 0b110100, 0b001000001, +- (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), +- "fadds $src1, $src2, $dst", +- [(set f32:$dst, (fadd f32:$src1, f32:$src2))]>; ++ (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), ++ "fadds $rs1, $rs2, $rd", ++ [(set f32:$rd, (fadd f32:$rs1, f32:$rs2))]>; + def FADDD : F3_3<2, 0b110100, 0b001000010, +- (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), +- "faddd $src1, $src2, $dst", +- [(set f64:$dst, (fadd f64:$src1, f64:$src2))]>; ++ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), ++ "faddd $rs1, $rs2, $rd", ++ [(set f64:$rd, (fadd f64:$rs1, f64:$rs2))]>; + def FADDQ : F3_3<2, 0b110100, 0b001000011, +- (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2), +- "faddq $src1, $src2, $dst", +- [(set f128:$dst, (fadd f128:$src1, f128:$src2))]>, ++ (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), ++ "faddq $rs1, $rs2, $rd", ++ [(set f128:$rd, (fadd f128:$rs1, f128:$rs2))]>, + Requires<[HasHardQuad]>; + + def FSUBS : F3_3<2, 0b110100, 0b001000101, +- (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), +- "fsubs $src1, $src2, $dst", +- [(set f32:$dst, (fsub f32:$src1, f32:$src2))]>; ++ (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), ++ "fsubs $rs1, $rs2, $rd", ++ [(set f32:$rd, (fsub f32:$rs1, f32:$rs2))]>; + def FSUBD : F3_3<2, 0b110100, 0b001000110, +- (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), +- "fsubd $src1, $src2, $dst", +- [(set f64:$dst, (fsub f64:$src1, f64:$src2))]>; ++ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), ++ "fsubd $rs1, $rs2, $rd", ++ [(set f64:$rd, (fsub f64:$rs1, f64:$rs2))]>; + def FSUBQ : F3_3<2, 0b110100, 0b001000111, +- (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2), +- "fsubq $src1, $src2, $dst", +- [(set f128:$dst, (fsub f128:$src1, f128:$src2))]>, ++ (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), ++ "fsubq $rs1, $rs2, $rd", ++ [(set f128:$rd, (fsub f128:$rs1, f128:$rs2))]>, + Requires<[HasHardQuad]>; + + + // Floating-point Multiply and Divide Instructions, p. 147 + def FMULS : F3_3<2, 0b110100, 0b001001001, +- (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), +- "fmuls $src1, $src2, $dst", +- [(set f32:$dst, (fmul f32:$src1, f32:$src2))]>; ++ (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), ++ "fmuls $rs1, $rs2, $rd", ++ [(set f32:$rd, (fmul f32:$rs1, f32:$rs2))]>; + def FMULD : F3_3<2, 0b110100, 0b001001010, +- (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), +- "fmuld $src1, $src2, $dst", +- [(set f64:$dst, (fmul f64:$src1, f64:$src2))]>; ++ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), ++ "fmuld $rs1, $rs2, $rd", ++ [(set f64:$rd, (fmul f64:$rs1, f64:$rs2))]>; + def FMULQ : F3_3<2, 0b110100, 0b001001011, +- (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2), +- "fmulq $src1, $src2, $dst", +- [(set f128:$dst, (fmul f128:$src1, f128:$src2))]>, ++ (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), ++ "fmulq $rs1, $rs2, $rd", ++ [(set f128:$rd, (fmul f128:$rs1, f128:$rs2))]>, + Requires<[HasHardQuad]>; + + def FSMULD : F3_3<2, 0b110100, 0b001101001, +- (outs DFPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), +- "fsmuld $src1, $src2, $dst", +- [(set f64:$dst, (fmul (fextend f32:$src1), +- (fextend f32:$src2)))]>; ++ (outs DFPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), ++ "fsmuld $rs1, $rs2, $rd", ++ [(set f64:$rd, (fmul (fextend f32:$rs1), ++ (fextend f32:$rs2)))]>; + def FDMULQ : F3_3<2, 0b110100, 0b001101110, +- (outs QFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), +- "fdmulq $src1, $src2, $dst", +- [(set f128:$dst, (fmul (fextend f64:$src1), +- (fextend f64:$src2)))]>, ++ (outs QFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), ++ "fdmulq $rs1, $rs2, $rd", ++ [(set f128:$rd, (fmul (fextend f64:$rs1), ++ (fextend f64:$rs2)))]>, + Requires<[HasHardQuad]>; + + def FDIVS : F3_3<2, 0b110100, 0b001001101, +- (outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2), +- "fdivs $src1, $src2, $dst", +- [(set f32:$dst, (fdiv f32:$src1, f32:$src2))]>; ++ (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), ++ "fdivs $rs1, $rs2, $rd", ++ [(set f32:$rd, (fdiv f32:$rs1, f32:$rs2))]>; + def FDIVD : F3_3<2, 0b110100, 0b001001110, +- (outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2), +- "fdivd $src1, $src2, $dst", +- [(set f64:$dst, (fdiv f64:$src1, f64:$src2))]>; ++ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), ++ "fdivd $rs1, $rs2, $rd", ++ [(set f64:$rd, (fdiv f64:$rs1, f64:$rs2))]>; + def FDIVQ : F3_3<2, 0b110100, 0b001001111, +- (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2), +- "fdivq $src1, $src2, $dst", +- [(set f128:$dst, (fdiv f128:$src1, f128:$src2))]>, ++ (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), ++ "fdivq $rs1, $rs2, $rd", ++ [(set f128:$rd, (fdiv f128:$rs1, f128:$rs2))]>, + Requires<[HasHardQuad]>; + + // Floating-point Compare Instructions, p. 148 +@@ -770,17 +770,17 @@ def FDIVQ : F3_3<2, 0b110100, 0b001001111, + + let Defs = [FCC] in { + def FCMPS : F3_3c<2, 0b110101, 0b001010001, +- (outs), (ins FPRegs:$src1, FPRegs:$src2), +- "fcmps $src1, $src2", +- [(SPcmpfcc f32:$src1, f32:$src2)]>; ++ (outs), (ins FPRegs:$rs1, FPRegs:$rs2), ++ "fcmps $rs1, $rs2", ++ [(SPcmpfcc f32:$rs1, f32:$rs2)]>; + def FCMPD : F3_3c<2, 0b110101, 0b001010010, +- (outs), (ins DFPRegs:$src1, DFPRegs:$src2), +- "fcmpd $src1, $src2", +- [(SPcmpfcc f64:$src1, f64:$src2)]>; ++ (outs), (ins DFPRegs:$rs1, DFPRegs:$rs2), ++ "fcmpd $rs1, $rs2", ++ [(SPcmpfcc f64:$rs1, f64:$rs2)]>; + def FCMPQ : F3_3c<2, 0b110101, 0b001010011, +- (outs), (ins QFPRegs:$src1, QFPRegs:$src2), +- "fcmpq $src1, $src2", +- [(SPcmpfcc f128:$src1, f128:$src2)]>, ++ (outs), (ins QFPRegs:$rs1, QFPRegs:$rs2), ++ "fcmpq $rs1, $rs2", ++ [(SPcmpfcc f128:$rs1, f128:$rs2)]>, + Requires<[HasHardQuad]>; + } + +@@ -892,29 +892,29 @@ let Predicates = [HasV9], Constraints = "$f = $rd" + // Floating-Point Move Instructions, p. 164 of the V9 manual. + let Predicates = [HasV9] in { + def FMOVD : F3_3u<2, 0b110100, 0b000000010, +- (outs DFPRegs:$dst), (ins DFPRegs:$src), +- "fmovd $src, $dst", []>; ++ (outs DFPRegs:$rd), (ins DFPRegs:$rs2), ++ "fmovd $rs2, $rd", []>; + def FMOVQ : F3_3u<2, 0b110100, 0b000000011, +- (outs QFPRegs:$dst), (ins QFPRegs:$src), +- "fmovq $src, $dst", []>, ++ (outs QFPRegs:$rd), (ins QFPRegs:$rs2), ++ "fmovq $rs2, $rd", []>, + Requires<[HasHardQuad]>; + def FNEGD : F3_3u<2, 0b110100, 0b000000110, +- (outs DFPRegs:$dst), (ins DFPRegs:$src), +- "fnegd $src, $dst", +- [(set f64:$dst, (fneg f64:$src))]>; ++ (outs DFPRegs:$rd), (ins DFPRegs:$rs2), ++ "fnegd $rs2, $rd", ++ [(set f64:$rd, (fneg f64:$rs2))]>; + def FNEGQ : F3_3u<2, 0b110100, 0b000000111, +- (outs QFPRegs:$dst), (ins QFPRegs:$src), +- "fnegq $src, $dst", +- [(set f128:$dst, (fneg f128:$src))]>, ++ (outs QFPRegs:$rd), (ins QFPRegs:$rs2), ++ "fnegq $rs2, $rd", ++ [(set f128:$rd, (fneg f128:$rs2))]>, + Requires<[HasHardQuad]>; + def FABSD : F3_3u<2, 0b110100, 0b000001010, +- (outs DFPRegs:$dst), (ins DFPRegs:$src), +- "fabsd $src, $dst", +- [(set f64:$dst, (fabs f64:$src))]>; ++ (outs DFPRegs:$rd), (ins DFPRegs:$rs2), ++ "fabsd $rs2, $rd", ++ [(set f64:$rd, (fabs f64:$rs2))]>; + def FABSQ : F3_3u<2, 0b110100, 0b000001011, +- (outs QFPRegs:$dst), (ins QFPRegs:$src), +- "fabsq $src, $dst", +- [(set f128:$dst, (fabs f128:$src))]>, ++ (outs QFPRegs:$rd), (ins QFPRegs:$rs2), ++ "fabsq $rs2, $rd", ++ [(set f128:$rd, (fabs f128:$rs2))]>, + Requires<[HasHardQuad]>; + } + +Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +=================================================================== +--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp ++++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +@@ -54,6 +54,8 @@ class SparcAsmParser : public MCTargetAsmParser { + SmallVectorImpl<MCParsedAsmOperand*> &Operands); + bool ParseDirective(AsmToken DirectiveID); + ++ virtual unsigned validateTargetOperandClass(MCParsedAsmOperand *Op, ++ unsigned Kind); + + // Custom parse functions for Sparc specific operands. + OperandMatchResultTy +@@ -67,8 +69,9 @@ class SparcAsmParser : public MCTargetAsmParser { + parseSparcAsmOperand(SparcOperand *&Operand); + + // returns true if Tok is matched to a register and returns register in RegNo. +- bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo, bool isDFP, +- bool isQFP); ++ bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo, ++ unsigned &RegKind); ++ + bool matchSparcAsmModifiers(const MCExpr *&EVal, SMLoc &EndLoc); + + public: +@@ -178,6 +181,16 @@ class SparcOperand : public MCParsedAsmOperand { + bool isMEMrr() const { return Kind == k_MemoryReg; } + bool isMEMri() const { return Kind == k_MemoryImm; } + ++ bool isFloatReg() const { ++ return (Kind == k_Register && Reg.Kind == rk_FloatReg); ++ } ++ ++ bool isFloatOrDoubleReg() const { ++ return (Kind == k_Register && (Reg.Kind == rk_FloatReg ++ || Reg.Kind == rk_DoubleReg)); ++ } ++ ++ + StringRef getToken() const { + assert(Kind == k_Token && "Invalid access!"); + return StringRef(Tok.Data, Tok.Length); +@@ -280,11 +293,11 @@ class SparcOperand : public MCParsedAsmOperand { + } + + static SparcOperand *CreateReg(unsigned RegNum, +- SparcOperand::RegisterKind Kind, ++ unsigned Kind, + SMLoc S, SMLoc E) { + SparcOperand *Op = new SparcOperand(k_Register); + Op->Reg.RegNum = RegNum; +- Op->Reg.Kind = Kind; ++ Op->Reg.Kind = (SparcOperand::RegisterKind)Kind; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; +@@ -298,6 +311,40 @@ class SparcOperand : public MCParsedAsmOperand { + return Op; + } + ++ static SparcOperand *MorphToDoubleReg(SparcOperand *Op) { ++ unsigned Reg = Op->getReg(); ++ assert(Op->Reg.Kind == rk_FloatReg); ++ unsigned regIdx = Reg - Sparc::F0; ++ if (regIdx % 2 || regIdx > 31) ++ return 0; ++ Op->Reg.RegNum = DoubleRegs[regIdx / 2]; ++ Op->Reg.Kind = rk_DoubleReg; ++ return Op; ++ } ++ ++ static SparcOperand *MorphToQuadReg(SparcOperand *Op) { ++ unsigned Reg = Op->getReg(); ++ unsigned regIdx = 0; ++ switch (Op->Reg.Kind) { ++ default: assert(0 && "Unexpected register kind!"); ++ case rk_FloatReg: ++ regIdx = Reg - Sparc::F0; ++ if (regIdx % 4 || regIdx > 31) ++ return 0; ++ Reg = QuadFPRegs[regIdx / 4]; ++ break; ++ case rk_DoubleReg: ++ regIdx = Reg - Sparc::D0; ++ if (regIdx % 2 || regIdx > 31) ++ return 0; ++ Reg = QuadFPRegs[regIdx / 2]; ++ break; ++ } ++ Op->Reg.RegNum = Reg; ++ Op->Reg.Kind = rk_QuadReg; ++ return Op; ++ } ++ + static SparcOperand *MorphToMEMrr(unsigned Base, SparcOperand *Op) { + unsigned offsetReg = Op->getReg(); + Op->Kind = k_MemoryReg; +@@ -383,7 +430,8 @@ ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SM + if (getLexer().getKind() != AsmToken::Percent) + return false; + Parser.Lex(); +- if (matchRegisterName(Tok, RegNo, false, false)) { ++ unsigned regKind = SparcOperand::rk_None; ++ if (matchRegisterName(Tok, RegNo, regKind)) { + Parser.Lex(); + return false; + } +@@ -537,13 +585,14 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand + case AsmToken::Percent: + Parser.Lex(); // Eat the '%'. + unsigned RegNo; +- if (matchRegisterName(Parser.getTok(), RegNo, false, false)) { ++ unsigned RegKind; ++ if (matchRegisterName(Parser.getTok(), RegNo, RegKind)) { + StringRef name = Parser.getTok().getString(); + Parser.Lex(); // Eat the identifier token. + E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + switch (RegNo) { + default: +- Op = SparcOperand::CreateReg(RegNo, SparcOperand::rk_None, S, E); ++ Op = SparcOperand::CreateReg(RegNo, RegKind, S, E); + break; + case Sparc::Y: + Op = SparcOperand::CreateToken("%y", S); +@@ -593,11 +642,11 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand + + bool SparcAsmParser::matchRegisterName(const AsmToken &Tok, + unsigned &RegNo, +- bool isDFP, +- bool isQFP) ++ unsigned &RegKind) + { + int64_t intVal = 0; + RegNo = 0; ++ RegKind = SparcOperand::rk_None; + if (Tok.is(AsmToken::Identifier)) { + StringRef name = Tok.getString(); + +@@ -604,21 +653,25 @@ bool SparcAsmParser::matchRegisterName(const AsmTo + // %fp + if (name.equals("fp")) { + RegNo = Sparc::I6; ++ RegKind = SparcOperand::rk_IntReg; + return true; + } + // %sp + if (name.equals("sp")) { + RegNo = Sparc::O6; ++ RegKind = SparcOperand::rk_IntReg; + return true; + } + + if (name.equals("y")) { + RegNo = Sparc::Y; ++ RegKind = SparcOperand::rk_Y; + return true; + } + + if (name.equals("icc")) { + RegNo = Sparc::ICC; ++ RegKind = SparcOperand::rk_CCReg; + return true; + } + +@@ -625,6 +678,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo + if (name.equals("xcc")) { + // FIXME:: check 64bit. + RegNo = Sparc::ICC; ++ RegKind = SparcOperand::rk_CCReg; + return true; + } + +@@ -634,6 +688,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo + && intVal < 4) { + // FIXME: check 64bit and handle %fcc1 - %fcc3 + RegNo = Sparc::FCC; ++ RegKind = SparcOperand::rk_CCReg; + return true; + } + +@@ -642,6 +697,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo + && !name.substr(1).getAsInteger(10, intVal) + && intVal < 8) { + RegNo = IntRegs[intVal]; ++ RegKind = SparcOperand::rk_IntReg; + return true; + } + // %o0 - %o7 +@@ -649,6 +705,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo + && !name.substr(1).getAsInteger(10, intVal) + && intVal < 8) { + RegNo = IntRegs[8 + intVal]; ++ RegKind = SparcOperand::rk_IntReg; + return true; + } + if (name.substr(0, 1).equals_lower("l") +@@ -655,6 +712,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo + && !name.substr(1).getAsInteger(10, intVal) + && intVal < 8) { + RegNo = IntRegs[16 + intVal]; ++ RegKind = SparcOperand::rk_IntReg; + return true; + } + if (name.substr(0, 1).equals_lower("i") +@@ -661,18 +719,14 @@ bool SparcAsmParser::matchRegisterName(const AsmTo + && !name.substr(1).getAsInteger(10, intVal) + && intVal < 8) { + RegNo = IntRegs[24 + intVal]; ++ RegKind = SparcOperand::rk_IntReg; + return true; + } + // %f0 - %f31 + if (name.substr(0, 1).equals_lower("f") + && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 32) { +- if (isDFP && (intVal%2 == 0)) { +- RegNo = DoubleRegs[intVal/2]; +- } else if (isQFP && (intVal%4 == 0)) { +- RegNo = QuadFPRegs[intVal/4]; +- } else { +- RegNo = FloatRegs[intVal]; +- } ++ RegNo = FloatRegs[intVal]; ++ RegKind = SparcOperand::rk_FloatReg; + return true; + } + // %f32 - %f62 +@@ -679,13 +733,9 @@ bool SparcAsmParser::matchRegisterName(const AsmTo + if (name.substr(0, 1).equals_lower("f") + && !name.substr(1, 2).getAsInteger(10, intVal) + && intVal >= 32 && intVal <= 62 && (intVal % 2 == 0)) { +- if (isDFP) { +- RegNo = DoubleRegs[16 + intVal/2]; +- } else if (isQFP && (intVal % 4 == 0)) { +- RegNo = QuadFPRegs[8 + intVal/4]; +- } else { +- return false; +- } ++ // FIXME: Check V9 ++ RegNo = DoubleRegs[16 + intVal/2]; ++ RegKind = SparcOperand::rk_DoubleReg; + return true; + } + +@@ -693,6 +743,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo + if (name.substr(0, 1).equals_lower("r") + && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 31) { + RegNo = IntRegs[intVal]; ++ RegKind = SparcOperand::rk_IntReg; + return true; + } + } +@@ -735,3 +786,26 @@ extern "C" void LLVMInitializeSparcAsmParser() { + #define GET_REGISTER_MATCHER + #define GET_MATCHER_IMPLEMENTATION + #include "SparcGenAsmMatcher.inc" ++ ++ ++ ++unsigned SparcAsmParser:: ++validateTargetOperandClass(MCParsedAsmOperand *GOp, ++ unsigned Kind) ++{ ++ SparcOperand *Op = (SparcOperand*)GOp; ++ if (Op->isFloatOrDoubleReg()) { ++ switch (Kind) { ++ default: break; ++ case MCK_DFPRegs: ++ if (!Op->isFloatReg() || SparcOperand::MorphToDoubleReg(Op)) ++ return MCTargetAsmParser::Match_Success; ++ break; ++ case MCK_QFPRegs: ++ if (SparcOperand::MorphToQuadReg(Op)) ++ return MCTargetAsmParser::Match_Success; ++ break; ++ } ++ } ++ return Match_InvalidOperand; ++} +Index: lib/Target/Sparc/SparcInstr64Bit.td +=================================================================== +--- lib/Target/Sparc/SparcInstr64Bit.td ++++ lib/Target/Sparc/SparcInstr64Bit.td +@@ -358,31 +358,31 @@ def FMOVQ_XCC : F4_3<0b110101, 0b000011, (outs QFP + let Predicates = [Is64Bit] in { + + def FXTOS : F3_3u<2, 0b110100, 0b010000100, +- (outs FPRegs:$dst), (ins DFPRegs:$src), +- "fxtos $src, $dst", +- [(set FPRegs:$dst, (SPxtof DFPRegs:$src))]>; ++ (outs FPRegs:$rd), (ins DFPRegs:$rs2), ++ "fxtos $rs2, $rd", ++ [(set FPRegs:$rd, (SPxtof DFPRegs:$rs2))]>; + def FXTOD : F3_3u<2, 0b110100, 0b010001000, +- (outs DFPRegs:$dst), (ins DFPRegs:$src), +- "fxtod $src, $dst", +- [(set DFPRegs:$dst, (SPxtof DFPRegs:$src))]>; ++ (outs DFPRegs:$rd), (ins DFPRegs:$rs2), ++ "fxtod $rs2, $rd", ++ [(set DFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>; + def FXTOQ : F3_3u<2, 0b110100, 0b010001100, +- (outs QFPRegs:$dst), (ins DFPRegs:$src), +- "fxtoq $src, $dst", +- [(set QFPRegs:$dst, (SPxtof DFPRegs:$src))]>, ++ (outs QFPRegs:$rd), (ins DFPRegs:$rs2), ++ "fxtoq $rs2, $rd", ++ [(set QFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>, + Requires<[HasHardQuad]>; + + def FSTOX : F3_3u<2, 0b110100, 0b010000001, +- (outs DFPRegs:$dst), (ins FPRegs:$src), +- "fstox $src, $dst", +- [(set DFPRegs:$dst, (SPftox FPRegs:$src))]>; ++ (outs DFPRegs:$rd), (ins FPRegs:$rs2), ++ "fstox $rs2, $rd", ++ [(set DFPRegs:$rd, (SPftox FPRegs:$rs2))]>; + def FDTOX : F3_3u<2, 0b110100, 0b010000010, +- (outs DFPRegs:$dst), (ins DFPRegs:$src), +- "fdtox $src, $dst", +- [(set DFPRegs:$dst, (SPftox DFPRegs:$src))]>; ++ (outs DFPRegs:$rd), (ins DFPRegs:$rs2), ++ "fdtox $rs2, $rd", ++ [(set DFPRegs:$rd, (SPftox DFPRegs:$rs2))]>; + def FQTOX : F3_3u<2, 0b110100, 0b010000011, +- (outs DFPRegs:$dst), (ins QFPRegs:$src), +- "fqtox $src, $dst", +- [(set DFPRegs:$dst, (SPftox QFPRegs:$src))]>, ++ (outs DFPRegs:$rd), (ins QFPRegs:$rs2), ++ "fqtox $rs2, $rd", ++ [(set DFPRegs:$rd, (SPftox QFPRegs:$rs2))]>, + Requires<[HasHardQuad]>; + + } // Predicates = [Is64Bit] +Index: test/MC/Disassembler/Sparc/sparc-fp.txt +=================================================================== +--- test/MC/Disassembler/Sparc/sparc-fp.txt ++++ test/MC/Disassembler/Sparc/sparc-fp.txt +@@ -0,0 +1,142 @@ ++# RUN: llvm-mc --disassemble %s -triple=sparc64-linux-gnu | FileCheck %s ++ ++ ++# CHECK: fitos %f0, %f4 ++0x89 0xa0 0x18 0x80 ++ ++# CHECK: fitod %f0, %f4 ++0x89 0xa0 0x19 0x00 ++ ++# CHECK: fitoq %f0, %f4 ++0x89 0xa0 0x19 0x80 ++ ++# CHECK: fstoi %f0, %f4 ++0x89 0xa0 0x1a 0x20 ++ ++# CHECK: fdtoi %f0, %f4 ++0x89 0xa0 0x1a 0x40 ++ ++# CHECK: fqtoi %f0, %f4 ++0x89 0xa0 0x1a 0x60 ++ ++# CHECK: fstod %f0, %f4 ++0x89 0xa0 0x19 0x20 ++# CHECK: fstoq %f0, %f4 ++0x89 0xa0 0x19 0xa0 ++ ++# CHECK: fdtos %f0, %f4 ++0x89 0xa0 0x18 0xc0 ++ ++# CHECK: fdtoq %f0, %f4 ++0x89 0xa0 0x19 0xc0 ++ ++# CHECK: fqtos %f0, %f4 ++0x89 0xa0 0x18 0xe0 ++ ++# CHECK: fqtod %f0, %f4 ++0x89 0xa0 0x19 0x60 ++ ++# CHECK: fmovs %f0, %f4 ++0x89 0xa0 0x00 0x20 ++ ++# CHECK: fmovd %f0, %f4 ++0x89 0xa0 0x00 0x40 ++ ++# CHECK: fmovq %f0, %f4 ++0x89 0xa0 0x00 0x60 ++ ++# CHECK: fnegs %f0, %f4 ++0x89 0xa0 0x00 0xa0 ++ ++# CHECK: fnegd %f0, %f4 ++0x89 0xa0 0x00 0xc0 ++ ++# CHECK: fnegq %f0, %f4 ++0x89 0xa0 0x00 0xe0 ++ ++# CHECK: fabss %f0, %f4 ++0x89 0xa0 0x01 0x20 ++ ++# CHECK: fabsd %f0, %f4 ++0x89 0xa0 0x01 0x40 ++ ++# CHECK: fabsq %f0, %f4 ++0x89 0xa0 0x01 0x60 ++ ++# CHECK: fsqrts %f0, %f4 ++0x89 0xa0 0x05 0x20 ++ ++# CHECK: fsqrtd %f0, %f4 ++0x89 0xa0 0x05 0x40 ++ ++# CHECK: fsqrtq %f0, %f4 ++0x89 0xa0 0x05 0x60 ++ ++# CHECK: fadds %f0, %f4, %f8 ++0x91 0xa0 0x08 0x24 ++ ++# CHECK: faddd %f0, %f4, %f8 ++0x91 0xa0 0x08 0x44 ++ ++# CHECK: faddq %f0, %f4, %f8 ++0x91 0xa0 0x08 0x64 ++ ++# CHECK: fsubs %f0, %f4, %f8 ++0x91 0xa0 0x08 0xa4 ++ ++# CHECK: fsubd %f0, %f4, %f8 ++0x91 0xa0 0x08 0xc4 ++ ++# CHECK: fsubq %f0, %f4, %f8 ++0x91 0xa0 0x08 0xe4 ++ ++# CHECK: fmuls %f0, %f4, %f8 ++0x91 0xa0 0x09 0x24 ++ ++# CHECK: fmuld %f0, %f4, %f8 ++0x91 0xa0 0x09 0x44 ++ ++# CHECK: fmulq %f0, %f4, %f8 ++0x91 0xa0 0x09 0x64 ++ ++# CHECK: fsmuld %f0, %f4, %f8 ++0x91 0xa0 0x0d 0x24 ++ ++# CHECK: fdmulq %f0, %f4, %f8 ++0x91 0xa0 0x0d 0xc4 ++ ++# CHECK: fdivs %f0, %f4, %f8 ++0x91 0xa0 0x09 0xa4 ++ ++# CHECK: fdivd %f0, %f4, %f8 ++0x91 0xa0 0x09 0xc4 ++ ++# CHECK: fdivq %f0, %f4, %f8 ++0x91 0xa0 0x09 0xe4 ++ ++# CHECK: fcmps %f0, %f4 ++0x81 0xa8 0x0a 0x24 ++ ++# CHECK: fcmpd %f0, %f4 ++0x81 0xa8 0x0a 0x44 ++ ++# CHECK: fcmpq %f0, %f4 ++0x81 0xa8 0x0a 0x64 ++ ++# CHECK: fxtos %f0, %f4 ++0x89 0xa0 0x10 0x80 ++ ++# CHECK: fxtod %f0, %f4 ++0x89 0xa0 0x11 0x00 ++ ++# CHECK: fxtoq %f0, %f4 ++0x89 0xa0 0x11 0x80 ++ ++# CHECK: fstox %f0, %f4 ++0x89 0xa0 0x10 0x20 ++ ++# CHECK: fdtox %f0, %f4 ++0x89 0xa0 0x10 0x40 ++ ++# CHECK: fqtox %f0, %f4 ++0x89 0xa0 0x10 0x60 +Index: test/MC/Sparc/sparc-fp-instructions.s +=================================================================== +--- test/MC/Sparc/sparc-fp-instructions.s ++++ test/MC/Sparc/sparc-fp-instructions.s +@@ -0,0 +1,113 @@ ++! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s ++ ++ ! CHECK: fitos %f0, %f4 ! encoding: [0x89,0xa0,0x18,0x80] ++ ! CHECK: fitod %f0, %f4 ! encoding: [0x89,0xa0,0x19,0x00] ++ ! CHECK: fitoq %f0, %f4 ! encoding: [0x89,0xa0,0x19,0x80] ++ fitos %f0, %f4 ++ fitod %f0, %f4 ++ fitoq %f0, %f4 ++ ++ ! CHECK: fstoi %f0, %f4 ! encoding: [0x89,0xa0,0x1a,0x20] ++ ! CHECK: fdtoi %f0, %f4 ! encoding: [0x89,0xa0,0x1a,0x40] ++ ! CHECK: fqtoi %f0, %f4 ! encoding: [0x89,0xa0,0x1a,0x60] ++ fstoi %f0, %f4 ++ fdtoi %f0, %f4 ++ fqtoi %f0, %f4 ++ ++ ! CHECK: fstod %f0, %f4 ! encoding: [0x89,0xa0,0x19,0x20] ++ ! CHECK: fstoq %f0, %f4 ! encoding: [0x89,0xa0,0x19,0xa0] ++ fstod %f0, %f4 ++ fstoq %f0, %f4 ++ ++ ! CHECK: fdtos %f0, %f4 ! encoding: [0x89,0xa0,0x18,0xc0] ++ ! CHECK: fdtoq %f0, %f4 ! encoding: [0x89,0xa0,0x19,0xc0] ++ fdtos %f0, %f4 ++ fdtoq %f0, %f4 ++ ++ ! CHECK: fqtos %f0, %f4 ! encoding: [0x89,0xa0,0x18,0xe0] ++ ! CHECK: fqtod %f0, %f4 ! encoding: [0x89,0xa0,0x19,0x60] ++ fqtos %f0, %f4 ++ fqtod %f0, %f4 ++ ++ ! CHECK: fmovs %f0, %f4 ! encoding: [0x89,0xa0,0x00,0x20] ++ ! CHECK: fmovd %f0, %f4 ! encoding: [0x89,0xa0,0x00,0x40] ++ ! CHECK: fmovq %f0, %f4 ! encoding: [0x89,0xa0,0x00,0x60] ++ fmovs %f0, %f4 ++ fmovd %f0, %f4 ++ fmovq %f0, %f4 ++ ++ ! CHECK: fnegs %f0, %f4 ! encoding: [0x89,0xa0,0x00,0xa0] ++ ! CHECK: fnegd %f0, %f4 ! encoding: [0x89,0xa0,0x00,0xc0] ++ ! CHECK: fnegq %f0, %f4 ! encoding: [0x89,0xa0,0x00,0xe0] ++ fnegs %f0, %f4 ++ fnegd %f0, %f4 ++ fnegq %f0, %f4 ++ ++ ! CHECK: fabss %f0, %f4 ! encoding: [0x89,0xa0,0x01,0x20] ++ ! CHECK: fabsd %f0, %f4 ! encoding: [0x89,0xa0,0x01,0x40] ++ ! CHECK: fabsq %f0, %f4 ! encoding: [0x89,0xa0,0x01,0x60] ++ fabss %f0, %f4 ++ fabsd %f0, %f4 ++ fabsq %f0, %f4 ++ ++ ! CHECK: fsqrts %f0, %f4 ! encoding: [0x89,0xa0,0x05,0x20] ++ ! CHECK: fsqrtd %f0, %f4 ! encoding: [0x89,0xa0,0x05,0x40] ++ ! CHECK: fsqrtq %f0, %f4 ! encoding: [0x89,0xa0,0x05,0x60] ++ fsqrts %f0, %f4 ++ fsqrtd %f0, %f4 ++ fsqrtq %f0, %f4 ++ ++ ! CHECK: fadds %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0x24] ++ ! CHECK: faddd %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0x44] ++ ! CHECK: faddq %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0x64] ++ fadds %f0, %f4, %f8 ++ faddd %f0, %f4, %f8 ++ faddq %f0, %f4, %f8 ++ ++ ! CHECK: fsubs %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0xa4] ++ ! CHECK: fsubd %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0xc4] ++ ! CHECK: fsubq %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0xe4] ++ fsubs %f0, %f4, %f8 ++ fsubd %f0, %f4, %f8 ++ fsubq %f0, %f4, %f8 ++ ++ ! CHECK: fmuls %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x09,0x24] ++ ! CHECK: fmuld %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x09,0x44] ++ ! CHECK: fmulq %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x09,0x64] ++ fmuls %f0, %f4, %f8 ++ fmuld %f0, %f4, %f8 ++ fmulq %f0, %f4, %f8 ++ ++ ! CHECK: fsmuld %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x0d,0x24] ++ ! CHECK: fdmulq %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x0d,0xc4] ++ fsmuld %f0, %f4, %f8 ++ fdmulq %f0, %f4, %f8 ++ ++ ! CHECK: fdivs %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x09,0xa4] ++ ! CHECK: fdivd %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x09,0xc4] ++ ! CHECK: fdivq %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x09,0xe4] ++ fdivs %f0, %f4, %f8 ++ fdivd %f0, %f4, %f8 ++ fdivq %f0, %f4, %f8 ++ ++ ! CHECK: fcmps %f0, %f4 ! encoding: [0x81,0xa8,0x0a,0x24] ++ ! CHECK: fcmpd %f0, %f4 ! encoding: [0x81,0xa8,0x0a,0x44] ++ ! CHECK: fcmpq %f0, %f4 ! encoding: [0x81,0xa8,0x0a,0x64] ++ fcmps %f0, %f4 ++ fcmpd %f0, %f4 ++ fcmpq %f0, %f4 ++ ++ ! CHECK: fxtos %f0, %f4 ! encoding: [0x89,0xa0,0x10,0x80] ++ ! CHECK: fxtod %f0, %f4 ! encoding: [0x89,0xa0,0x11,0x00] ++ ! CHECK: fxtoq %f0, %f4 ! encoding: [0x89,0xa0,0x11,0x80] ++ fxtos %f0, %f4 ++ fxtod %f0, %f4 ++ fxtoq %f0, %f4 ++ ++ ! CHECK: fstox %f0, %f4 ! encoding: [0x89,0xa0,0x10,0x20] ++ ! CHECK: fdtox %f0, %f4 ! encoding: [0x89,0xa0,0x10,0x40] ++ ! CHECK: fqtox %f0, %f4 ! encoding: [0x89,0xa0,0x10,0x60] ++ fstox %f0, %f4 ++ fdtox %f0, %f4 ++ fqtox %f0, %f4 ++ diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199061-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199061-sparc.diff new file mode 100644 index 0000000..4a8e5b8 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199061-sparc.diff @@ -0,0 +1,126 @@ +Pull in r199061 from upstream llvm trunk (by Jakob Stoklund Olesen): + + Handle bundled terminators in isBlockOnlyReachableByFallthrough. + + Targets like SPARC and MIPS have delay slots and normally bundle the + delay slot instruction with the corresponding terminator. + + Teach isBlockOnlyReachableByFallthrough to find any MBB operands on + bundled terminators so SPARC doesn't need to specialize this function. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/CodeGen/SPARC/missinglabel.ll +=================================================================== +--- test/CodeGen/SPARC/missinglabel.ll ++++ test/CodeGen/SPARC/missinglabel.ll +@@ -0,0 +1,23 @@ ++; RUN: llc < %s -verify-machineinstrs | FileCheck %s ++target datalayout = "E-m:e-i64:64-n32:64-S128" ++target triple = "sparc64-unknown-linux-gnu" ++ ++define void @f() align 2 { ++entry: ++; CHECK: %xcc, .LBB0_1 ++ %cmp = icmp eq i64 undef, 0 ++ br i1 %cmp, label %targetblock, label %cond.false ++ ++cond.false: ++ unreachable ++ ++; CHECK: .LBB0_1: ! %targetblock ++targetblock: ++ br i1 undef, label %cond.false.i83, label %exit.i85 ++ ++cond.false.i83: ++ unreachable ++ ++exit.i85: ++ unreachable ++} +Index: lib/Target/Sparc/SparcAsmPrinter.cpp +=================================================================== +--- lib/Target/Sparc/SparcAsmPrinter.cpp ++++ lib/Target/Sparc/SparcAsmPrinter.cpp +@@ -65,10 +65,6 @@ namespace { + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); +- +- virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) +- const; +- + }; + } // end of anonymous namespace + +@@ -390,37 +386,6 @@ bool SparcAsmPrinter::PrintAsmMemoryOperand(const + return false; + } + +-/// isBlockOnlyReachableByFallthough - Return true if the basic block has +-/// exactly one predecessor and the control transfer mechanism between +-/// the predecessor and this block is a fall-through. +-/// +-/// This overrides AsmPrinter's implementation to handle delay slots. +-bool SparcAsmPrinter:: +-isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const { +- // If this is a landing pad, it isn't a fall through. If it has no preds, +- // then nothing falls through to it. +- if (MBB->isLandingPad() || MBB->pred_empty()) +- return false; +- +- // If there isn't exactly one predecessor, it can't be a fall through. +- MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI; +- ++PI2; +- if (PI2 != MBB->pred_end()) +- return false; +- +- // The predecessor has to be immediately before this block. +- const MachineBasicBlock *Pred = *PI; +- +- if (!Pred->isLayoutSuccessor(MBB)) +- return false; +- +- // Check if the last terminator is an unconditional branch. +- MachineBasicBlock::const_iterator I = Pred->end(); +- while (I != Pred->begin() && !(--I)->isTerminator()) +- ; // Noop +- return I == Pred->end() || !I->isBarrier(); +-} +- + // Force static initialization. + extern "C" void LLVMInitializeSparcAsmPrinter() { + RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget); +Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp +=================================================================== +--- lib/CodeGen/AsmPrinter/AsmPrinter.cpp ++++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp +@@ -23,6 +23,7 @@ + #include "llvm/CodeGen/MachineConstantPool.h" + #include "llvm/CodeGen/MachineFrameInfo.h" + #include "llvm/CodeGen/MachineFunction.h" ++#include "llvm/CodeGen/MachineInstrBundle.h" + #include "llvm/CodeGen/MachineJumpTableInfo.h" + #include "llvm/CodeGen/MachineLoopInfo.h" + #include "llvm/CodeGen/MachineModuleInfo.h" +@@ -2221,14 +2222,13 @@ isBlockOnlyReachableByFallthrough(const MachineBas + if (!MI.isBranch() || MI.isIndirectBranch()) + return false; + +- // If we are the operands of one of the branches, this is not +- // a fall through. +- for (MachineInstr::mop_iterator OI = MI.operands_begin(), +- OE = MI.operands_end(); OI != OE; ++OI) { +- const MachineOperand& OP = *OI; +- if (OP.isJTI()) ++ // If we are the operands of one of the branches, this is not a fall ++ // through. Note that targets with delay slots will usually bundle ++ // terminators with the delay slot instruction. ++ for (ConstMIBundleOperands OP(&MI); OP.isValid(); ++OP) { ++ if (OP->isJTI()) + return false; +- if (OP.isMBB() && OP.getMBB() == MBB) ++ if (OP->isMBB() && OP->getMBB() == MBB) + return false; + } + } diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199186-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199186-sparc.diff new file mode 100644 index 0000000..167aa6a --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199186-sparc.diff @@ -0,0 +1,28 @@ +Pull in r199186 from upstream llvm trunk (by Jakob Stoklund Olesen): + + Switch the NEON register class from QPR to DPair. + + The already allocatable DPair superclass contains odd-even D register + pair in addition to the even-odd pairs in the QPR register class. There + is no reason to constrain the set of D register pairs that can be used + for NEON values. Any NEON instructions that require a Q register will + automatically constrain the register class to QPR. + + The allocation order for DPair begins with the QPR registers, so + register allocation is unlikely to change much. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/ARM/ARMISelLowering.cpp +=================================================================== +--- lib/Target/ARM/ARMISelLowering.cpp ++++ lib/Target/ARM/ARMISelLowering.cpp +@@ -156,7 +156,7 @@ void ARMTargetLowering::addDRTypeForNEON(MVT VT) { + } + + void ARMTargetLowering::addQRTypeForNEON(MVT VT) { +- addRegisterClass(VT, &ARM::QPRRegClass); ++ addRegisterClass(VT, &ARM::DPairRegClass); + addTypeForNEON(VT, MVT::v2f64, MVT::v4i32); + } + diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199187-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199187-sparc.diff new file mode 100644 index 0000000..bfc1cfc --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199187-sparc.diff @@ -0,0 +1,81 @@ +Pull in r199187 from upstream llvm trunk (by Jakob Stoklund Olesen): + + Always let value types influence register classes. + + When creating a virtual register for a def, the value type should be + used to pick the register class. If we only use the register class + constraint on the instruction, we might pick a too large register class. + + Some registers can store values of different sizes. For example, the x86 + xmm registers can hold f32, f64, and 128-bit vectors. The three + different value sizes are represented by register classes with identical + register sets: FR32, FR64, and VR128. These register classes have + different spill slot sizes, so it is important to use the right one. + + The register class constraint on an instruction doesn't necessarily care + about the size of the value its defining. The value type determines + that. + + This fixes a problem where InstrEmitter was picking 32-bit register + classes for 64-bit values on SPARC. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/CodeGen/SPARC/spillsize.ll +=================================================================== +--- test/CodeGen/SPARC/spillsize.ll ++++ test/CodeGen/SPARC/spillsize.ll +@@ -0,0 +1,25 @@ ++; RUN: llc < %s -verify-machineinstrs | FileCheck %s ++target datalayout = "E-m:e-i64:64-n32:64-S128" ++target triple = "sparcv9" ++ ++; CHECK-LABEL: spill4 ++; This function spills two values: %p and the materialized large constant. ++; Both must use 8-byte spill and fill instructions. ++; CHECK: stx %{{..}}, [%fp+ ++; CHECK: stx %{{..}}, [%fp+ ++; CHECK: ldx [%fp+ ++; CHECK: ldx [%fp+ ++define void @spill4(i64* nocapture %p) { ++entry: ++ %val0 = load i64* %p ++ %cmp0 = icmp ult i64 %val0, 385672958347594845 ++ %cm80 = zext i1 %cmp0 to i64 ++ store i64 %cm80, i64* %p, align 8 ++ tail call void asm sideeffect "", "~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{g2},~{g3},~{g4},~{g5},~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o7}"() ++ %arrayidx1 = getelementptr inbounds i64* %p, i64 1 ++ %val = load i64* %arrayidx1 ++ %cmp = icmp ult i64 %val, 385672958347594845 ++ %cm8 = select i1 %cmp, i64 10, i64 20 ++ store i64 %cm8, i64* %arrayidx1, align 8 ++ ret void ++} +Index: lib/CodeGen/SelectionDAG/InstrEmitter.cpp +=================================================================== +--- lib/CodeGen/SelectionDAG/InstrEmitter.cpp ++++ lib/CodeGen/SelectionDAG/InstrEmitter.cpp +@@ -220,10 +220,19 @@ void InstrEmitter::CreateVirtualRegisters(SDNode * + unsigned VRBase = 0; + const TargetRegisterClass *RC = + TRI->getAllocatableClass(TII->getRegClass(II, i, TRI, *MF)); +- // If the register class is unknown for the given definition, then try to +- // infer one from the value type. +- if (!RC && i < NumResults) +- RC = TLI->getRegClassFor(Node->getSimpleValueType(i)); ++ // Always let the value type influence the used register class. The ++ // constraints on the instruction may be too lax to represent the value ++ // type correctly. For example, a 64-bit float (X86::FR64) can't live in ++ // the 32-bit float super-class (X86::FR32). ++ if (i < NumResults && TLI->isTypeLegal(Node->getSimpleValueType(i))) { ++ const TargetRegisterClass *VTRC = ++ TLI->getRegClassFor(Node->getSimpleValueType(i)); ++ if (RC) ++ VTRC = TRI->getCommonSubClass(RC, VTRC); ++ if (VTRC) ++ RC = VTRC; ++ } ++ + if (II.OpInfo[i].isOptionalDef()) { + // Optional def must be a physical register. + unsigned NumResults = CountResults(Node); diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199775-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199775-sparc.diff new file mode 100644 index 0000000..489f457 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199775-sparc.diff @@ -0,0 +1,200 @@ +Pull in r199775 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Do not add PC to _GLOBAL_OFFSET_TABLE_ address to access GOT in absolute code. + Fixes PR#18521 + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcAsmPrinter.cpp +=================================================================== +--- lib/Target/Sparc/SparcAsmPrinter.cpp ++++ lib/Target/Sparc/SparcAsmPrinter.cpp +@@ -65,18 +65,24 @@ namespace { + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, + unsigned AsmVariant, const char *ExtraCode, + raw_ostream &O); ++ ++ void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI); ++ + }; + } // end of anonymous namespace + +-static MCOperand createPCXCallOP(MCSymbol *Label, +- MCContext &OutContext) +-{ +- const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Label, ++static MCOperand createSparcMCOperand(SparcMCExpr::VariantKind Kind, ++ MCSymbol *Sym, MCContext &OutContext) { ++ const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::Create(Sym, + OutContext); +- const SparcMCExpr *expr = SparcMCExpr::Create(SparcMCExpr::VK_Sparc_None, +- MCSym, OutContext); ++ const SparcMCExpr *expr = SparcMCExpr::Create(Kind, MCSym, OutContext); + return MCOperand::CreateExpr(expr); ++ + } ++static MCOperand createPCXCallOP(MCSymbol *Label, ++ MCContext &OutContext) { ++ return createSparcMCOperand(SparcMCExpr::VK_Sparc_None, Label, OutContext); ++} + + static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind, + MCSymbol *GOTLabel, MCSymbol *StartLabel, +@@ -115,43 +121,101 @@ static void EmitSETHI(MCStreamer &OutStreamer, + OutStreamer.EmitInstruction(SETHIInst); + } + +-static void EmitOR(MCStreamer &OutStreamer, MCOperand &RS1, +- MCOperand &Imm, MCOperand &RD) ++static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode, ++ MCOperand &RS1, MCOperand &Src2, MCOperand &RD) + { +- MCInst ORInst; +- ORInst.setOpcode(SP::ORri); +- ORInst.addOperand(RD); +- ORInst.addOperand(RS1); +- ORInst.addOperand(Imm); +- OutStreamer.EmitInstruction(ORInst); ++ MCInst Inst; ++ Inst.setOpcode(Opcode); ++ Inst.addOperand(RD); ++ Inst.addOperand(RS1); ++ Inst.addOperand(Src2); ++ OutStreamer.EmitInstruction(Inst); + } + ++static void EmitOR(MCStreamer &OutStreamer, ++ MCOperand &RS1, MCOperand &Imm, MCOperand &RD) { ++ EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD); ++} ++ + static void EmitADD(MCStreamer &OutStreamer, +- MCOperand &RS1, MCOperand &RS2, MCOperand &RD) +-{ +- MCInst ADDInst; +- ADDInst.setOpcode(SP::ADDrr); +- ADDInst.addOperand(RD); +- ADDInst.addOperand(RS1); +- ADDInst.addOperand(RS2); +- OutStreamer.EmitInstruction(ADDInst); ++ MCOperand &RS1, MCOperand &RS2, MCOperand &RD) { ++ EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD); + } + +-static void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI, +- MCStreamer &OutStreamer, +- MCContext &OutContext) ++static void EmitSHL(MCStreamer &OutStreamer, ++ MCOperand &RS1, MCOperand &Imm, MCOperand &RD) { ++ EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD); ++} ++ ++ ++static void EmitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym, ++ SparcMCExpr::VariantKind HiKind, ++ SparcMCExpr::VariantKind LoKind, ++ MCOperand &RD, ++ MCContext &OutContext) { ++ ++ MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext); ++ MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext); ++ EmitSETHI(OutStreamer, hi, RD); ++ EmitOR(OutStreamer, RD, lo, RD); ++} ++ ++void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI) + { +- const MachineOperand &MO = MI->getOperand(0); +- MCSymbol *StartLabel = OutContext.CreateTempSymbol(); +- MCSymbol *EndLabel = OutContext.CreateTempSymbol(); +- MCSymbol *SethiLabel = OutContext.CreateTempSymbol(); + MCSymbol *GOTLabel = + OutContext.GetOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_")); + ++ const MachineOperand &MO = MI->getOperand(0); + assert(MO.getReg() != SP::O7 && + "%o7 is assigned as destination for getpcx!"); + + MCOperand MCRegOP = MCOperand::CreateReg(MO.getReg()); ++ ++ ++ if (TM.getRelocationModel() != Reloc::PIC_) { ++ // Just load the address of GOT to MCRegOP. ++ switch(TM.getCodeModel()) { ++ default: ++ llvm_unreachable("Unsupported absolute code model"); ++ case CodeModel::Small: ++ EmitHiLo(OutStreamer, GOTLabel, ++ SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO, ++ MCRegOP, OutContext); ++ break; ++ case CodeModel::Medium: { ++ EmitHiLo(OutStreamer, GOTLabel, ++ SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44, ++ MCRegOP, OutContext); ++ MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(12, ++ OutContext)); ++ EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP); ++ MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44, ++ GOTLabel, OutContext); ++ EmitOR(OutStreamer, MCRegOP, lo, MCRegOP); ++ break; ++ } ++ case CodeModel::Large: { ++ EmitHiLo(OutStreamer, GOTLabel, ++ SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM, ++ MCRegOP, OutContext); ++ MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(32, ++ OutContext)); ++ EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP); ++ // Use register %o7 to load the lower 32 bits. ++ MCOperand RegO7 = MCOperand::CreateReg(SP::O7); ++ EmitHiLo(OutStreamer, GOTLabel, ++ SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO, ++ RegO7, OutContext); ++ EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP); ++ } ++ } ++ return; ++ } ++ ++ MCSymbol *StartLabel = OutContext.CreateTempSymbol(); ++ MCSymbol *EndLabel = OutContext.CreateTempSymbol(); ++ MCSymbol *SethiLabel = OutContext.CreateTempSymbol(); ++ + MCOperand RegO7 = MCOperand::CreateReg(SP::O7); + + // <StartLabel>: +@@ -187,7 +251,7 @@ void SparcAsmPrinter::EmitInstruction(const Machin + // FIXME: Debug Value. + return; + case SP::GETPCX: +- LowerGETPCXAndEmitMCInsts(MI, OutStreamer, OutContext); ++ LowerGETPCXAndEmitMCInsts(MI); + return; + } + MachineBasicBlock::const_instr_iterator I = MI; +Index: test/CodeGen/SPARC/tls.ll +=================================================================== +--- test/CodeGen/SPARC/tls.ll ++++ test/CodeGen/SPARC/tls.ll +@@ -38,8 +38,7 @@ entry: + + + ; v8abs-LABEL: test_tls_extern +-; v8abs: or {{%[goli][0-7]}}, %lo(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[PC:%[goli][0-7]]] +-; v8abs: add [[PC]], %o7, %[[GOTBASE:[goli][0-7]]] ++; v8abs: or {{%[goli][0-7]}}, %lo(_GLOBAL_OFFSET_TABLE_), %[[GOTBASE:[goli][0-7]]] + ; v8abs: sethi %tie_hi22(extern_symbol), [[R1:%[goli][0-7]]] + ; v8abs: add [[R1]], %tie_lo10(extern_symbol), %[[R2:[goli][0-7]]] + ; v8abs: ld [%[[GOTBASE]]+%[[R2]]], [[R3:%[goli][0-7]]], %tie_ld(extern_symbol) +@@ -47,8 +46,7 @@ entry: + ; v8abs: ld [%[[R4]]] + + ; v9abs-LABEL: test_tls_extern +-; v9abs: or {{%[goli][0-7]}}, %lo(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[PC:%[goli][0-7]]] +-; v9abs: add [[PC]], %o7, %[[GOTBASE:[goli][0-7]]] ++; v9abs: or {{%[goli][0-7]}}, %l44(_GLOBAL_OFFSET_TABLE_), %[[GOTBASE:[goli][0-7]]] + ; v9abs: sethi %tie_hi22(extern_symbol), [[R1:%[goli][0-7]]] + ; v9abs: add [[R1]], %tie_lo10(extern_symbol), %[[R2:[goli][0-7]]] + ; v9abs: ldx [%[[GOTBASE]]+%[[R2]]], [[R3:%[goli][0-7]]], %tie_ldx(extern_symbol) diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199781-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199781-sparc.diff new file mode 100644 index 0000000..0417410 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199781-sparc.diff @@ -0,0 +1,142 @@ +Pull in r199781 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add support for inline assembly constraint 'I'. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/CodeGen/SPARC/inlineasm.ll +=================================================================== +--- test/CodeGen/SPARC/inlineasm.ll ++++ test/CodeGen/SPARC/inlineasm.ll +@@ -0,0 +1,35 @@ ++; RUN: llc -march=sparc <%s | FileCheck %s ++ ++; CHECK-LABEL: test_constraint_r ++; CHECK: add %o1, %o0, %o0 ++define i32 @test_constraint_r(i32 %a, i32 %b) { ++entry: ++ %0 = tail call i32 asm sideeffect "add $2, $1, $0", "=r,r,r"(i32 %a, i32 %b) ++ ret i32 %0 ++} ++ ++; CHECK-LABEL: test_constraint_I ++; CHECK: add %o0, 1023, %o0 ++define i32 @test_constraint_I(i32 %a) { ++entry: ++ %0 = tail call i32 asm sideeffect "add $1, $2, $0", "=r,r,rI"(i32 %a, i32 1023) ++ ret i32 %0 ++} ++ ++; CHECK-LABEL: test_constraint_I_neg ++; CHECK: add %o0, -4096, %o0 ++define i32 @test_constraint_I_neg(i32 %a) { ++entry: ++ %0 = tail call i32 asm sideeffect "add $1, $2, $0", "=r,r,rI"(i32 %a, i32 -4096) ++ ret i32 %0 ++} ++ ++; CHECK-LABEL: test_constraint_I_largeimm ++; CHECK: sethi 9, [[R0:%[gilo][0-7]]] ++; CHECK: or [[R0]], 784, [[R1:%[gilo][0-7]]] ++; CHECK: add %o0, [[R1]], %o0 ++define i32 @test_constraint_I_largeimm(i32 %a) { ++entry: ++ %0 = tail call i32 asm sideeffect "add $1, $2, $0", "=r,r,rI"(i32 %a, i32 10000) ++ ret i32 %0 ++} +Index: lib/Target/Sparc/SparcISelLowering.h +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.h ++++ lib/Target/Sparc/SparcISelLowering.h +@@ -73,6 +73,13 @@ namespace llvm { + virtual const char *getTargetNodeName(unsigned Opcode) const; + + ConstraintType getConstraintType(const std::string &Constraint) const; ++ ConstraintWeight ++ getSingleConstraintMatchWeight(AsmOperandInfo &info, ++ const char *constraint) const; ++ void LowerAsmOperandForConstraint(SDValue Op, ++ std::string &Constraint, ++ std::vector<SDValue> &Ops, ++ SelectionDAG &DAG) const; + std::pair<unsigned, const TargetRegisterClass*> + getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const; + +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -2918,6 +2918,8 @@ SparcTargetLowering::getConstraintType(const std:: + switch (Constraint[0]) { + default: break; + case 'r': return C_RegisterClass; ++ case 'I': // SIMM13 ++ return C_Other; + } + } + +@@ -2924,6 +2926,64 @@ SparcTargetLowering::getConstraintType(const std:: + return TargetLowering::getConstraintType(Constraint); + } + ++TargetLowering::ConstraintWeight SparcTargetLowering:: ++getSingleConstraintMatchWeight(AsmOperandInfo &info, ++ const char *constraint) const { ++ ConstraintWeight weight = CW_Invalid; ++ Value *CallOperandVal = info.CallOperandVal; ++ // If we don't have a value, we can't do a match, ++ // but allow it at the lowest weight. ++ if (CallOperandVal == NULL) ++ return CW_Default; ++ ++ // Look at the constraint type. ++ switch (*constraint) { ++ default: ++ weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint); ++ break; ++ case 'I': // SIMM13 ++ if (ConstantInt *C = dyn_cast<ConstantInt>(info.CallOperandVal)) { ++ if (isInt<13>(C->getSExtValue())) ++ weight = CW_Constant; ++ } ++ break; ++ } ++ return weight; ++} ++ ++/// LowerAsmOperandForConstraint - Lower the specified operand into the Ops ++/// vector. If it is invalid, don't add anything to Ops. ++void SparcTargetLowering:: ++LowerAsmOperandForConstraint(SDValue Op, ++ std::string &Constraint, ++ std::vector<SDValue> &Ops, ++ SelectionDAG &DAG) const { ++ SDValue Result(0, 0); ++ ++ // Only support length 1 constraints for now. ++ if (Constraint.length() > 1) ++ return; ++ ++ char ConstraintLetter = Constraint[0]; ++ switch (ConstraintLetter) { ++ default: break; ++ case 'I': ++ if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) { ++ if (isInt<13>(C->getSExtValue())) { ++ Result = DAG.getTargetConstant(C->getSExtValue(), Op.getValueType()); ++ break; ++ } ++ return; ++ } ++ } ++ ++ if (Result.getNode()) { ++ Ops.push_back(Result); ++ return; ++ } ++ TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG); ++} ++ + std::pair<unsigned, const TargetRegisterClass*> + SparcTargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint, + MVT VT) const { diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199786-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199786-sparc.diff new file mode 100644 index 0000000..844e4e4 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199786-sparc.diff @@ -0,0 +1,55 @@ +Pull in r199786 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add support for inline assembly constraints which specify registers by their aliases. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -2992,6 +2992,26 @@ SparcTargetLowering::getRegForInlineAsmConstraint( + case 'r': + return std::make_pair(0U, &SP::IntRegsRegClass); + } ++ } else if (!Constraint.empty() && Constraint.size() <= 5 ++ && Constraint[0] == '{' && *(Constraint.end()-1) == '}') { ++ // constraint = '{r<d>}' ++ // Remove the braces from around the name. ++ StringRef name(Constraint.data()+1, Constraint.size()-2); ++ // Handle register aliases: ++ // r0-r7 -> g0-g7 ++ // r8-r15 -> o0-o7 ++ // r16-r23 -> l0-l7 ++ // r24-r31 -> i0-i7 ++ uint64_t intVal = 0; ++ if (name.substr(0, 1).equals("r") ++ && !name.substr(1).getAsInteger(10, intVal) && intVal <= 31) { ++ const char regTypes[] = { 'g', 'o', 'l', 'i' }; ++ char regType = regTypes[intVal/8]; ++ char regIdx = '0' + (intVal % 8); ++ char tmp[] = { '{', regType, regIdx, '}', 0 }; ++ std::string newConstraint = std::string(tmp); ++ return TargetLowering::getRegForInlineAsmConstraint(newConstraint, VT); ++ } + } + + return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT); +Index: test/CodeGen/SPARC/inlineasm.ll +=================================================================== +--- test/CodeGen/SPARC/inlineasm.ll ++++ test/CodeGen/SPARC/inlineasm.ll +@@ -33,3 +33,13 @@ entry: + %0 = tail call i32 asm sideeffect "add $1, $2, $0", "=r,r,rI"(i32 %a, i32 10000) + ret i32 %0 + } ++ ++; CHECK-LABEL: test_constraint_reg ++; CHECK: ldda [%o1] 43, %g2 ++; CHECK: ldda [%o1] 43, %g3 ++define void @test_constraint_reg(i32 %s, i32* %ptr) { ++entry: ++ %0 = tail call i64 asm sideeffect "ldda [$1] $2, $0", "={r2},r,n"(i32* %ptr, i32 43) ++ %1 = tail call i64 asm sideeffect "ldda [$1] $2, $0", "={g3},r,n"(i32* %ptr, i32 43) ++ ret void ++} diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199940-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199940-sparc.diff new file mode 100644 index 0000000..e171799 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199940-sparc.diff @@ -0,0 +1,21 @@ +Pull in r199940 from upstream llvm trunk (by Eric Christopher): + + Fix out of bounds access to the double regs array. Given the + code this looks correct, but could use review. The previous + was definitely not correct. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +=================================================================== +--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp ++++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +@@ -734,7 +734,7 @@ bool SparcAsmParser::matchRegisterName(const AsmTo + && !name.substr(1, 2).getAsInteger(10, intVal) + && intVal >= 32 && intVal <= 62 && (intVal % 2 == 0)) { + // FIXME: Check V9 +- RegNo = DoubleRegs[16 + intVal/2]; ++ RegNo = DoubleRegs[intVal/2]; + RegKind = SparcOperand::rk_DoubleReg; + return true; + } diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199974-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199974-sparc.diff new file mode 100644 index 0000000..0951995 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199974-sparc.diff @@ -0,0 +1,54 @@ +Pull in r199974 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Correct quad register list in the asm parser. + Add test cases to check parsing of v9 double registers and their aliased quad registers. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/MC/Disassembler/Sparc/sparc-fp.txt +=================================================================== +--- test/MC/Disassembler/Sparc/sparc-fp.txt ++++ test/MC/Disassembler/Sparc/sparc-fp.txt +@@ -81,6 +81,12 @@ + # CHECK: faddq %f0, %f4, %f8 + 0x91 0xa0 0x08 0x64 + ++# CHECK: faddd %f32, %f34, %f62 ++0xbf 0xa0 0x48 0x43 ++ ++# CHECK: faddq %f32, %f36, %f60 ++0xbb 0xa0 0x48 0x65 ++ + # CHECK: fsubs %f0, %f4, %f8 + 0x91 0xa0 0x08 0xa4 + +Index: test/MC/Sparc/sparc-fp-instructions.s +=================================================================== +--- test/MC/Sparc/sparc-fp-instructions.s ++++ test/MC/Sparc/sparc-fp-instructions.s +@@ -64,6 +64,12 @@ + faddd %f0, %f4, %f8 + faddq %f0, %f4, %f8 + ++ ! make sure we can handle V9 double registers and their aliased quad registers. ++ ! CHECK: faddd %f32, %f34, %f62 ! encoding: [0xbf,0xa0,0x48,0x43] ++ ! CHECK: faddq %f32, %f36, %f60 ! encoding: [0xbb,0xa0,0x48,0x65] ++ faddd %f32, %f34, %f62 ++ faddq %f32, %f36, %f60 ++ + ! CHECK: fsubs %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0xa4] + ! CHECK: fsubd %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0xc4] + ! CHECK: fsubq %f0, %f4, %f8 ! encoding: [0x91,0xa0,0x08,0xe4] +Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +=================================================================== +--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp ++++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +@@ -117,7 +117,7 @@ class SparcAsmParser : public MCTargetAsmParser { + static unsigned QuadFPRegs[32] = { + Sparc::Q0, Sparc::Q1, Sparc::Q2, Sparc::Q3, + Sparc::Q4, Sparc::Q5, Sparc::Q6, Sparc::Q7, +- Sparc::Q8, Sparc::Q7, Sparc::Q8, Sparc::Q9, ++ Sparc::Q8, Sparc::Q9, Sparc::Q10, Sparc::Q11, + Sparc::Q12, Sparc::Q13, Sparc::Q14, Sparc::Q15 }; + + diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199975-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199975-sparc.diff new file mode 100644 index 0000000..b1dec41 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199975-sparc.diff @@ -0,0 +1,344 @@ +Pull in r199975 from upstream llvm trunk (by Jakob Stoklund Olesen): + + Implement atomicrmw operations in 32 and 64 bits for SPARCv9. + + These all use the compare-and-swap CASA/CASXA instructions. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/CodeGen/SPARC/atomics.ll +=================================================================== +--- test/CodeGen/SPARC/atomics.ll ++++ test/CodeGen/SPARC/atomics.ll +@@ -1,4 +1,4 @@ +-; RUN: llc < %s -march=sparcv9 | FileCheck %s ++; RUN: llc < %s -march=sparcv9 -verify-machineinstrs | FileCheck %s + + ; CHECK-LABEL: test_atomic_i32 + ; CHECK: ld [%o0] +@@ -61,3 +61,84 @@ entry: + %b = atomicrmw xchg i32* %ptr, i32 42 monotonic + ret i32 %b + } ++ ++; CHECK-LABEL: test_load_add_32 ++; CHECK: membar ++; CHECK: add ++; CHECK: cas [%o0] ++; CHECK: membar ++define zeroext i32 @test_load_add_32(i32* %p, i32 zeroext %v) { ++entry: ++ %0 = atomicrmw add i32* %p, i32 %v seq_cst ++ ret i32 %0 ++} ++ ++; CHECK-LABEL: test_load_sub_64 ++; CHECK: membar ++; CHECK: sub ++; CHECK: casx [%o0] ++; CHECK: membar ++define zeroext i64 @test_load_sub_64(i64* %p, i64 zeroext %v) { ++entry: ++ %0 = atomicrmw sub i64* %p, i64 %v seq_cst ++ ret i64 %0 ++} ++ ++; CHECK-LABEL: test_load_xor_32 ++; CHECK: membar ++; CHECK: xor ++; CHECK: cas [%o0] ++; CHECK: membar ++define zeroext i32 @test_load_xor_32(i32* %p, i32 zeroext %v) { ++entry: ++ %0 = atomicrmw xor i32* %p, i32 %v seq_cst ++ ret i32 %0 ++} ++ ++; CHECK-LABEL: test_load_and_32 ++; CHECK: membar ++; CHECK: and ++; CHECK-NOT: xor ++; CHECK: cas [%o0] ++; CHECK: membar ++define zeroext i32 @test_load_and_32(i32* %p, i32 zeroext %v) { ++entry: ++ %0 = atomicrmw and i32* %p, i32 %v seq_cst ++ ret i32 %0 ++} ++ ++; CHECK-LABEL: test_load_nand_32 ++; CHECK: membar ++; CHECK: and ++; CHECK: xor ++; CHECK: cas [%o0] ++; CHECK: membar ++define zeroext i32 @test_load_nand_32(i32* %p, i32 zeroext %v) { ++entry: ++ %0 = atomicrmw nand i32* %p, i32 %v seq_cst ++ ret i32 %0 ++} ++ ++; CHECK-LABEL: test_load_max_64 ++; CHECK: membar ++; CHECK: cmp ++; CHECK: movg %xcc ++; CHECK: casx [%o0] ++; CHECK: membar ++define zeroext i64 @test_load_max_64(i64* %p, i64 zeroext %v) { ++entry: ++ %0 = atomicrmw max i64* %p, i64 %v seq_cst ++ ret i64 %0 ++} ++ ++; CHECK-LABEL: test_load_umin_32 ++; CHECK: membar ++; CHECK: cmp ++; CHECK: movleu %icc ++; CHECK: cas [%o0] ++; CHECK: membar ++define zeroext i32 @test_load_umin_32(i32* %p, i32 zeroext %v) { ++entry: ++ %0 = atomicrmw umin i32* %p, i32 %v seq_cst ++ ret i32 %0 ++} +Index: lib/Target/Sparc/SparcInstr64Bit.td +=================================================================== +--- lib/Target/Sparc/SparcInstr64Bit.td ++++ lib/Target/Sparc/SparcInstr64Bit.td +@@ -438,6 +438,31 @@ def : Pat<(atomic_store ADDRri:$dst, i64:$val), (S + + } // Predicates = [Is64Bit] + ++let usesCustomInserter = 1, hasCtrlDep = 1, mayLoad = 1, mayStore = 1, ++ Defs = [ICC] in ++multiclass AtomicRMW<SDPatternOperator op32, SDPatternOperator op64> { ++ ++ def _32 : Pseudo<(outs IntRegs:$rd), ++ (ins ptr_rc:$addr, IntRegs:$rs2), "", ++ [(set i32:$rd, (op32 iPTR:$addr, i32:$rs2))]>; ++ ++ let Predicates = [Is64Bit] in ++ def _64 : Pseudo<(outs I64Regs:$rd), ++ (ins ptr_rc:$addr, I64Regs:$rs2), "", ++ [(set i64:$rd, (op64 iPTR:$addr, i64:$rs2))]>; ++} ++ ++defm ATOMIC_LOAD_ADD : AtomicRMW<atomic_load_add_32, atomic_load_add_64>; ++defm ATOMIC_LOAD_SUB : AtomicRMW<atomic_load_sub_32, atomic_load_sub_64>; ++defm ATOMIC_LOAD_AND : AtomicRMW<atomic_load_and_32, atomic_load_and_64>; ++defm ATOMIC_LOAD_OR : AtomicRMW<atomic_load_or_32, atomic_load_or_64>; ++defm ATOMIC_LOAD_XOR : AtomicRMW<atomic_load_xor_32, atomic_load_xor_64>; ++defm ATOMIC_LOAD_NAND : AtomicRMW<atomic_load_nand_32, atomic_load_nand_64>; ++defm ATOMIC_LOAD_MIN : AtomicRMW<atomic_load_min_32, atomic_load_min_64>; ++defm ATOMIC_LOAD_MAX : AtomicRMW<atomic_load_max_32, atomic_load_max_64>; ++defm ATOMIC_LOAD_UMIN : AtomicRMW<atomic_load_umin_32, atomic_load_umin_64>; ++defm ATOMIC_LOAD_UMAX : AtomicRMW<atomic_load_umax_32, atomic_load_umax_64>; ++ + // Global addresses, constant pool entries + let Predicates = [Is64Bit] in { + +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -2831,11 +2831,6 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) cons + MachineBasicBlock * + SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, + MachineBasicBlock *BB) const { +- const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); +- unsigned BROpcode; +- unsigned CC; +- DebugLoc dl = MI->getDebugLoc(); +- // Figure out the conditional branch opcode to use for this select_cc. + switch (MI->getOpcode()) { + default: llvm_unreachable("Unknown SELECT_CC!"); + case SP::SELECT_CC_Int_ICC: +@@ -2842,17 +2837,64 @@ SparcTargetLowering::EmitInstrWithCustomInserter(M + case SP::SELECT_CC_FP_ICC: + case SP::SELECT_CC_DFP_ICC: + case SP::SELECT_CC_QFP_ICC: +- BROpcode = SP::BCOND; +- break; ++ return expandSelectCC(MI, BB, SP::BCOND); + case SP::SELECT_CC_Int_FCC: + case SP::SELECT_CC_FP_FCC: + case SP::SELECT_CC_DFP_FCC: + case SP::SELECT_CC_QFP_FCC: +- BROpcode = SP::FBCOND; +- break; ++ return expandSelectCC(MI, BB, SP::FBCOND); ++ ++ case SP::ATOMIC_LOAD_ADD_32: ++ return expandAtomicRMW(MI, BB, SP::ADDrr); ++ case SP::ATOMIC_LOAD_ADD_64: ++ return expandAtomicRMW(MI, BB, SP::ADDXrr); ++ case SP::ATOMIC_LOAD_SUB_32: ++ return expandAtomicRMW(MI, BB, SP::SUBrr); ++ case SP::ATOMIC_LOAD_SUB_64: ++ return expandAtomicRMW(MI, BB, SP::SUBXrr); ++ case SP::ATOMIC_LOAD_AND_32: ++ return expandAtomicRMW(MI, BB, SP::ANDrr); ++ case SP::ATOMIC_LOAD_AND_64: ++ return expandAtomicRMW(MI, BB, SP::ANDXrr); ++ case SP::ATOMIC_LOAD_OR_32: ++ return expandAtomicRMW(MI, BB, SP::ORrr); ++ case SP::ATOMIC_LOAD_OR_64: ++ return expandAtomicRMW(MI, BB, SP::ORXrr); ++ case SP::ATOMIC_LOAD_XOR_32: ++ return expandAtomicRMW(MI, BB, SP::XORrr); ++ case SP::ATOMIC_LOAD_XOR_64: ++ return expandAtomicRMW(MI, BB, SP::XORXrr); ++ case SP::ATOMIC_LOAD_NAND_32: ++ return expandAtomicRMW(MI, BB, SP::ANDrr); ++ case SP::ATOMIC_LOAD_NAND_64: ++ return expandAtomicRMW(MI, BB, SP::ANDXrr); ++ ++ case SP::ATOMIC_LOAD_MAX_32: ++ return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_G); ++ case SP::ATOMIC_LOAD_MAX_64: ++ return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_G); ++ case SP::ATOMIC_LOAD_MIN_32: ++ return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_LE); ++ case SP::ATOMIC_LOAD_MIN_64: ++ return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_LE); ++ case SP::ATOMIC_LOAD_UMAX_32: ++ return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_GU); ++ case SP::ATOMIC_LOAD_UMAX_64: ++ return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_GU); ++ case SP::ATOMIC_LOAD_UMIN_32: ++ return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_LEU); ++ case SP::ATOMIC_LOAD_UMIN_64: ++ return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_LEU); + } ++} + +- CC = (SPCC::CondCodes)MI->getOperand(3).getImm(); ++MachineBasicBlock* ++SparcTargetLowering::expandSelectCC(MachineInstr *MI, ++ MachineBasicBlock *BB, ++ unsigned BROpcode) const { ++ const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); ++ DebugLoc dl = MI->getDebugLoc(); ++ unsigned CC = (SPCC::CondCodes)MI->getOperand(3).getImm(); + + // To "insert" a SELECT_CC instruction, we actually have to insert the diamond + // control-flow pattern. The incoming instruction knows the destination vreg +@@ -2906,6 +2948,100 @@ SparcTargetLowering::EmitInstrWithCustomInserter(M + return BB; + } + ++MachineBasicBlock* ++SparcTargetLowering::expandAtomicRMW(MachineInstr *MI, ++ MachineBasicBlock *MBB, ++ unsigned Opcode, ++ unsigned CondCode) const { ++ const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); ++ MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo(); ++ DebugLoc DL = MI->getDebugLoc(); ++ ++ // MI is an atomic read-modify-write instruction of the form: ++ // ++ // rd = atomicrmw<op> addr, rs2 ++ // ++ // All three operands are registers. ++ unsigned DestReg = MI->getOperand(0).getReg(); ++ unsigned AddrReg = MI->getOperand(1).getReg(); ++ unsigned Rs2Reg = MI->getOperand(2).getReg(); ++ ++ // SelectionDAG has already inserted memory barriers before and after MI, so ++ // we simply have to implement the operatiuon in terms of compare-and-swap. ++ // ++ // %val0 = load %addr ++ // loop: ++ // %val = phi %val0, %dest ++ // %upd = op %val, %rs2 ++ // %dest = cas %addr, %upd, %val ++ // cmp %val, %dest ++ // bne loop ++ // done: ++ // ++ bool is64Bit = SP::I64RegsRegClass.hasSubClassEq(MRI.getRegClass(DestReg)); ++ const TargetRegisterClass *ValueRC = ++ is64Bit ? &SP::I64RegsRegClass : &SP::IntRegsRegClass; ++ unsigned Val0Reg = MRI.createVirtualRegister(ValueRC); ++ ++ BuildMI(*MBB, MI, DL, TII.get(is64Bit ? SP::LDXri : SP::LDri), Val0Reg) ++ .addReg(AddrReg).addImm(0); ++ ++ // Split the basic block MBB before MI and insert the loop block in the hole. ++ MachineFunction::iterator MFI = MBB; ++ const BasicBlock *LLVM_BB = MBB->getBasicBlock(); ++ MachineFunction *MF = MBB->getParent(); ++ MachineBasicBlock *LoopMBB = MF->CreateMachineBasicBlock(LLVM_BB); ++ MachineBasicBlock *DoneMBB = MF->CreateMachineBasicBlock(LLVM_BB); ++ ++MFI; ++ MF->insert(MFI, LoopMBB); ++ MF->insert(MFI, DoneMBB); ++ ++ // Move MI and following instructions to DoneMBB. ++ DoneMBB->splice(DoneMBB->begin(), MBB, MI, MBB->end()); ++ DoneMBB->transferSuccessorsAndUpdatePHIs(MBB); ++ ++ // Connect the CFG again. ++ MBB->addSuccessor(LoopMBB); ++ LoopMBB->addSuccessor(LoopMBB); ++ LoopMBB->addSuccessor(DoneMBB); ++ ++ // Build the loop block. ++ unsigned ValReg = MRI.createVirtualRegister(ValueRC); ++ unsigned UpdReg = MRI.createVirtualRegister(ValueRC); ++ ++ BuildMI(LoopMBB, DL, TII.get(SP::PHI), ValReg) ++ .addReg(Val0Reg).addMBB(MBB) ++ .addReg(DestReg).addMBB(LoopMBB); ++ ++ if (CondCode) { ++ // This is one of the min/max operations. We need a CMPrr followed by a ++ // MOVXCC/MOVICC. ++ BuildMI(LoopMBB, DL, TII.get(SP::CMPrr)).addReg(ValReg).addReg(Rs2Reg); ++ BuildMI(LoopMBB, DL, TII.get(Opcode), UpdReg) ++ .addReg(ValReg).addReg(Rs2Reg).addImm(CondCode); ++ } else { ++ BuildMI(LoopMBB, DL, TII.get(Opcode), UpdReg) ++ .addReg(ValReg).addReg(Rs2Reg); ++ } ++ ++ if (MI->getOpcode() == SP::ATOMIC_LOAD_NAND_32 || ++ MI->getOpcode() == SP::ATOMIC_LOAD_NAND_64) { ++ unsigned TmpReg = UpdReg; ++ UpdReg = MRI.createVirtualRegister(ValueRC); ++ BuildMI(LoopMBB, DL, TII.get(SP::XORri), UpdReg).addReg(TmpReg).addImm(-1); ++ } ++ ++ BuildMI(LoopMBB, DL, TII.get(is64Bit ? SP::CASXrr : SP::CASrr), DestReg) ++ .addReg(AddrReg).addReg(UpdReg).addReg(ValReg) ++ .setMemRefs(MI->memoperands_begin(), MI->memoperands_end()); ++ BuildMI(LoopMBB, DL, TII.get(SP::CMPrr)).addReg(ValReg).addReg(DestReg); ++ BuildMI(LoopMBB, DL, TII.get(is64Bit ? SP::BPXCC : SP::BCOND)) ++ .addMBB(LoopMBB).addImm(SPCC::ICC_NE); ++ ++ MI->eraseFromParent(); ++ return DoneMBB; ++} ++ + //===----------------------------------------------------------------------===// + // Sparc Inline Assembly Support + //===----------------------------------------------------------------------===// +Index: lib/Target/Sparc/SparcISelLowering.h +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.h ++++ lib/Target/Sparc/SparcISelLowering.h +@@ -165,6 +165,13 @@ namespace llvm { + virtual void ReplaceNodeResults(SDNode *N, + SmallVectorImpl<SDValue>& Results, + SelectionDAG &DAG) const; ++ ++ MachineBasicBlock *expandSelectCC(MachineInstr *MI, MachineBasicBlock *BB, ++ unsigned BROpcode) const; ++ MachineBasicBlock *expandAtomicRMW(MachineInstr *MI, ++ MachineBasicBlock *BB, ++ unsigned Opcode, ++ unsigned CondCode = 0) const; + }; + } // end namespace llvm + diff --git a/contrib/llvm/patches/patch-r262261-llvm-r199977-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r199977-sparc.diff new file mode 100644 index 0000000..166b5da --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r199977-sparc.diff @@ -0,0 +1,377 @@ +Pull in r199977 from upstream llvm trunk (by Venkatraman Govindaraju): + + [SparcV9] Add support for JIT in Sparc64. + With this change, all supported tests in test/ExecutionEngine pass in sparcv9. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcJITInfo.cpp +=================================================================== +--- lib/Target/Sparc/SparcJITInfo.cpp ++++ lib/Target/Sparc/SparcJITInfo.cpp +@@ -12,8 +12,9 @@ + //===----------------------------------------------------------------------===// + #define DEBUG_TYPE "jit" + #include "SparcJITInfo.h" ++#include "Sparc.h" + #include "SparcRelocations.h" +- ++#include "llvm/ADT/SmallVector.h" + #include "llvm/CodeGen/JITCodeEmitter.h" + #include "llvm/Support/Memory.h" + +@@ -35,18 +36,17 @@ extern "C" { + "SparcCompilationCallback:\n" + // Save current register window. + "\tsave %sp, -192, %sp\n" +- // stubaddr+4 is in %g1. ++ // stubaddr is in %g1. + "\tcall SparcCompilationCallbackC\n" +- "\t sub %g1, 4, %o0\n" ++ "\t mov %g1, %o0\n" + // restore original register window and + // copy %o0 to %g1 +- "\t restore %o0, 0, %g1\n" ++ "\trestore %o0, 0, %g1\n" + // call the new stub + "\tjmp %g1\n" + "\t nop\n" + "\t.size SparcCompilationCallback, .-SparcCompilationCallback" + ); +- + #else + void SparcCompilationCallback() { + llvm_unreachable( +@@ -55,33 +55,120 @@ extern "C" { + #endif + } + +-#define HI(Val) (((unsigned)(Val)) >> 10) +-#define LO(Val) (((unsigned)(Val)) & 0x3FF) + + #define SETHI_INST(imm, rd) (0x01000000 | ((rd) << 25) | ((imm) & 0x3FFFFF)) + #define JMP_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x38 << 19) \ + | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) + #define NOP_INST SETHI_INST(0, 0) ++#define OR_INST_I(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x02 << 19) \ ++ | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) ++#define OR_INST_R(rs1, rs2, rd) (0x80000000 | ((rd) << 25) | (0x02 << 19) \ ++ | ((rs1) << 14) | (0 << 13) | ((rs2) & 0x1F)) ++#define RDPC_INST(rd) (0x80000000 | ((rd) << 25) | (0x28 << 19) \ ++ | (5 << 14)) ++#define LDX_INST(rs1, imm, rd) (0xC0000000 | ((rd) << 25) | (0x0B << 19) \ ++ | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) ++#define SLLX_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x25 << 19) \ ++ | ((rs1) << 14) | (3 << 12) | ((imm) & 0x3F)) ++#define SUB_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x04 << 19) \ ++ | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) ++#define XOR_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x03 << 19) \ ++ | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) ++#define BA_INST(tgt) (0x10800000 | ((tgt) & 0x3FFFFF)) + ++// Emit instructions to jump to Addr and store the starting address of ++// the instructions emitted in the scratch register. ++static void emitInstrForIndirectJump(intptr_t Addr, ++ unsigned scratch, ++ SmallVectorImpl<uint32_t> &Insts) { ++ ++ if (isInt<13>(Addr)) { ++ // Emit: jmpl %g0+Addr, <scratch> ++ // nop ++ Insts.push_back(JMP_INST(0, LO10(Addr), scratch)); ++ Insts.push_back(NOP_INST); ++ return; ++ } ++ ++ if (isUInt<32>(Addr)) { ++ // Emit: sethi %hi(Addr), scratch ++ // jmpl scratch+%lo(Addr), scratch ++ // sub scratch, 4, scratch ++ Insts.push_back(SETHI_INST(HI22(Addr), scratch)); ++ Insts.push_back(JMP_INST(scratch, LO10(Addr), scratch)); ++ Insts.push_back(SUB_INST(scratch, 4, scratch)); ++ return; ++ } ++ ++ if (Addr < 0 && isInt<33>(Addr)) { ++ // Emit: sethi %hix(Addr), scratch) ++ // xor scratch, %lox(Addr), scratch ++ // jmpl scratch+0, scratch ++ // sub scratch, 8, scratch ++ Insts.push_back(SETHI_INST(HIX22(Addr), scratch)); ++ Insts.push_back(XOR_INST(scratch, LOX10(Addr), scratch)); ++ Insts.push_back(JMP_INST(scratch, 0, scratch)); ++ Insts.push_back(SUB_INST(scratch, 8, scratch)); ++ return; ++ } ++ ++ // Emit: rd %pc, scratch ++ // ldx [scratch+16], scratch ++ // jmpl scratch+0, scratch ++ // sub scratch, 8, scratch ++ // <Addr: 8 byte> ++ Insts.push_back(RDPC_INST(scratch)); ++ Insts.push_back(LDX_INST(scratch, 16, scratch)); ++ Insts.push_back(JMP_INST(scratch, 0, scratch)); ++ Insts.push_back(SUB_INST(scratch, 8, scratch)); ++ Insts.push_back((uint32_t)(((int64_t)Addr) >> 32) & 0xffffffff); ++ Insts.push_back((uint32_t)(Addr & 0xffffffff)); ++ ++ // Instruction sequence without rdpc instruction ++ // 7 instruction and 2 scratch register ++ // Emit: sethi %hh(Addr), scratch ++ // or scratch, %hm(Addr), scratch ++ // sllx scratch, 32, scratch ++ // sethi %hi(Addr), scratch2 ++ // or scratch, scratch2, scratch ++ // jmpl scratch+%lo(Addr), scratch ++ // sub scratch, 20, scratch ++ // Insts.push_back(SETHI_INST(HH22(Addr), scratch)); ++ // Insts.push_back(OR_INST_I(scratch, HM10(Addr), scratch)); ++ // Insts.push_back(SLLX_INST(scratch, 32, scratch)); ++ // Insts.push_back(SETHI_INST(HI22(Addr), scratch2)); ++ // Insts.push_back(OR_INST_R(scratch, scratch2, scratch)); ++ // Insts.push_back(JMP_INST(scratch, LO10(Addr), scratch)); ++ // Insts.push_back(SUB_INST(scratch, 20, scratch)); ++} ++ + extern "C" void *SparcCompilationCallbackC(intptr_t StubAddr) { + // Get the address of the compiled code for this function. + intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr); + + // Rewrite the function stub so that we don't end up here every time we +- // execute the call. We're replacing the first three instructions of the +- // stub with code that jumps to the compiled function: +- // sethi %hi(NewVal), %g1 +- // jmp %g1+%lo(NewVal) +- // nop ++ // execute the call. We're replacing the stub instructions with code ++ // that jumps to the compiled function: + +- *(intptr_t *)(StubAddr) = SETHI_INST(HI(NewVal), 1); +- *(intptr_t *)(StubAddr + 4) = JMP_INST(1, LO(NewVal), 0); +- *(intptr_t *)(StubAddr + 8) = NOP_INST; ++ SmallVector<uint32_t, 8> Insts; ++ intptr_t diff = (NewVal - StubAddr) >> 2; ++ if (isInt<22>(diff)) { ++ // Use branch instruction to jump ++ Insts.push_back(BA_INST(diff)); ++ Insts.push_back(NOP_INST); ++ } else { ++ // Otherwise, use indirect jump to the compiled function ++ emitInstrForIndirectJump(NewVal, 1, Insts); ++ } + +- sys::Memory::InvalidateInstructionCache((void*) StubAddr, 12); ++ for (unsigned i = 0, e = Insts.size(); i != e; ++i) ++ *(uint32_t *)(StubAddr + i*4) = Insts[i]; ++ ++ sys::Memory::InvalidateInstructionCache((void*) StubAddr, Insts.size() * 4); + return (void*)StubAddr; + } + ++ + void SparcJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { + assert(0 && "FIXME: Implement SparcJITInfo::replaceMachineCodeForFunction"); + } +@@ -88,10 +175,10 @@ void SparcJITInfo::replaceMachineCodeForFunction(v + + + TargetJITInfo::StubLayout SparcJITInfo::getStubLayout() { +- // The stub contains 3 4-byte instructions, aligned at 4 bytes. See +- // emitFunctionStub for details. +- +- StubLayout Result = { 3*4, 4 }; ++ // The stub contains maximum of 4 4-byte instructions and 8 bytes for address, ++ // aligned at 32 bytes. ++ // See emitFunctionStub and emitInstrForIndirectJump for details. ++ StubLayout Result = { 4*4 + 8, 32 }; + return Result; + } + +@@ -98,32 +185,41 @@ TargetJITInfo::StubLayout SparcJITInfo::getStubLay + void *SparcJITInfo::emitFunctionStub(const Function *F, void *Fn, + JITCodeEmitter &JCE) + { +- JCE.emitAlignment(4); ++ JCE.emitAlignment(32); + void *Addr = (void*) (JCE.getCurrentPCValue()); +- if (!sys::Memory::setRangeWritable(Addr, 12)) +- llvm_unreachable("ERROR: Unable to mark stub writable."); + ++ intptr_t CurrentAddr = (intptr_t)Addr; + intptr_t EmittedAddr; +- if (Fn != (void*)(intptr_t)SparcCompilationCallback) ++ SmallVector<uint32_t, 8> Insts; ++ if (Fn != (void*)(intptr_t)SparcCompilationCallback) { + EmittedAddr = (intptr_t)Fn; +- else ++ intptr_t diff = (EmittedAddr - CurrentAddr) >> 2; ++ if (isInt<22>(diff)) { ++ Insts.push_back(BA_INST(diff)); ++ Insts.push_back(NOP_INST); ++ } ++ } else { + EmittedAddr = (intptr_t)SparcCompilationCallback; ++ } + +- // sethi %hi(EmittedAddr), %g1 +- // jmp %g1+%lo(EmittedAddr), %g1 +- // nop ++ if (Insts.size() == 0) ++ emitInstrForIndirectJump(EmittedAddr, 1, Insts); + +- JCE.emitWordBE(SETHI_INST(HI(EmittedAddr), 1)); +- JCE.emitWordBE(JMP_INST(1, LO(EmittedAddr), 1)); +- JCE.emitWordBE(NOP_INST); + +- sys::Memory::InvalidateInstructionCache(Addr, 12); +- if (!sys::Memory::setRangeExecutable(Addr, 12)) ++ if (!sys::Memory::setRangeWritable(Addr, 4 * Insts.size())) ++ llvm_unreachable("ERROR: Unable to mark stub writable."); ++ ++ for (unsigned i = 0, e = Insts.size(); i != e; ++i) ++ JCE.emitWordBE(Insts[i]); ++ ++ sys::Memory::InvalidateInstructionCache(Addr, 4 * Insts.size()); ++ if (!sys::Memory::setRangeExecutable(Addr, 4 * Insts.size())) + llvm_unreachable("ERROR: Unable to mark stub executable."); + + return Addr; + } + ++ + TargetJITInfo::LazyResolverFn + SparcJITInfo::getLazyResolverFunction(JITCompilerFn F) { + JITCompilerFunction = F; +@@ -159,6 +255,27 @@ void SparcJITInfo::relocate(void *Function, Machin + case SP::reloc_sparc_pc19: + ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x7ffff; + break; ++ ++ case SP::reloc_sparc_h44: ++ ResultPtr = (ResultPtr >> 22) & 0x3fffff; ++ break; ++ ++ case SP::reloc_sparc_m44: ++ ResultPtr = (ResultPtr >> 12) & 0x3ff; ++ break; ++ ++ case SP::reloc_sparc_l44: ++ ResultPtr = (ResultPtr & 0xfff); ++ break; ++ ++ case SP::reloc_sparc_hh: ++ ResultPtr = (((int64_t)ResultPtr) >> 42) & 0x3fffff; ++ break; ++ ++ case SP::reloc_sparc_hm: ++ ResultPtr = (((int64_t)ResultPtr) >> 32) & 0x3ff; ++ break; ++ + } + *((unsigned*) RelocPos) |= (unsigned) ResultPtr; + } +Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +@@ -68,9 +68,13 @@ static MCCodeGenInfo *createSparcMCCodeGenInfo(Str + CodeGenOpt::Level OL) { + MCCodeGenInfo *X = new MCCodeGenInfo(); + +- // The default 32-bit code model is abs32/pic32. +- if (CM == CodeModel::Default) +- CM = RM == Reloc::PIC_ ? CodeModel::Medium : CodeModel::Small; ++ // The default 32-bit code model is abs32/pic32 and the default 32-bit ++ // code model for JIT is abs32. ++ switch (CM) { ++ default: break; ++ case CodeModel::Default: ++ case CodeModel::JITDefault: CM = CodeModel::Small; break; ++ } + + X->InitMCCodeGenInfo(RM, CM, OL); + return X; +@@ -81,9 +85,17 @@ static MCCodeGenInfo *createSparcV9MCCodeGenInfo(S + CodeGenOpt::Level OL) { + MCCodeGenInfo *X = new MCCodeGenInfo(); + +- // The default 64-bit code model is abs44/pic32. +- if (CM == CodeModel::Default) +- CM = CodeModel::Medium; ++ // The default 64-bit code model is abs44/pic32 and the default 64-bit ++ // code model for JIT is abs64. ++ switch (CM) { ++ default: break; ++ case CodeModel::Default: ++ CM = RM == Reloc::PIC_ ? CodeModel::Small : CodeModel::Medium; ++ break; ++ case CodeModel::JITDefault: ++ CM = CodeModel::Large; ++ break; ++ } + + X->InitMCCodeGenInfo(RM, CM, OL); + return X; +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -1810,7 +1810,6 @@ SDValue SparcTargetLowering::makeAddress(SDValue O + switch(getTargetMachine().getCodeModel()) { + default: + llvm_unreachable("Unsupported absolute code model"); +- case CodeModel::JITDefault: + case CodeModel::Small: + // abs32. + return makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG); +Index: lib/Target/Sparc/SparcCodeEmitter.cpp +=================================================================== +--- lib/Target/Sparc/SparcCodeEmitter.cpp ++++ lib/Target/Sparc/SparcCodeEmitter.cpp +@@ -207,11 +207,11 @@ unsigned SparcCodeEmitter::getRelocation(const Mac + case SPII::MO_NO_FLAG: break; + case SPII::MO_LO: return SP::reloc_sparc_lo; + case SPII::MO_HI: return SP::reloc_sparc_hi; +- case SPII::MO_H44: +- case SPII::MO_M44: +- case SPII::MO_L44: +- case SPII::MO_HH: +- case SPII::MO_HM: assert(0 && "FIXME: Implement Medium/Large code model."); ++ case SPII::MO_H44: return SP::reloc_sparc_h44; ++ case SPII::MO_M44: return SP::reloc_sparc_m44; ++ case SPII::MO_L44: return SP::reloc_sparc_l44; ++ case SPII::MO_HH: return SP::reloc_sparc_hh; ++ case SPII::MO_HM: return SP::reloc_sparc_hm; + } + + unsigned Opc = MI.getOpcode(); +Index: lib/Target/Sparc/SparcRelocations.h +=================================================================== +--- lib/Target/Sparc/SparcRelocations.h ++++ lib/Target/Sparc/SparcRelocations.h +@@ -33,7 +33,22 @@ namespace llvm { + reloc_sparc_pc22 = 4, + + // reloc_sparc_pc22 - pc rel. 19 bits for branch with icc/xcc +- reloc_sparc_pc19 = 5 ++ reloc_sparc_pc19 = 5, ++ ++ // reloc_sparc_h44 - 43-22 bits ++ reloc_sparc_h44 = 6, ++ ++ // reloc_sparc_m44 - 21-12 bits ++ reloc_sparc_m44 = 7, ++ ++ // reloc_sparc_l44 - lower 12 bits ++ reloc_sparc_l44 = 8, ++ ++ // reloc_sparc_hh - 63-42 bits ++ reloc_sparc_hh = 9, ++ ++ // reloc_sparc_hm - 41-32 bits ++ reloc_sparc_hm = 10 + }; + } + } diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200103-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200103-sparc.diff new file mode 100644 index 0000000..a2fd7d2 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200103-sparc.diff @@ -0,0 +1,49 @@ +Pull in r200103 from upstream llvm trunk (by Venkatraman Govindaraju): + + Missing ELF relocations for Sparc. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: include/llvm/Support/ELF.h +=================================================================== +--- include/llvm/Support/ELF.h ++++ include/llvm/Support/ELF.h +@@ -1143,7 +1143,37 @@ enum { + R_SPARC_L44 = 52, + R_SPARC_REGISTER = 53, + R_SPARC_UA64 = 54, +- R_SPARC_UA16 = 55 ++ R_SPARC_UA16 = 55, ++ R_SPARC_UA16 = 55, ++ R_SPARC_TLS_GD_HI22 = 56, ++ R_SPARC_TLS_GD_LO10 = 57, ++ R_SPARC_TLS_GD_ADD = 58, ++ R_SPARC_TLS_GD_CALL = 59, ++ R_SPARC_TLS_LDM_HI22 = 60, ++ R_SPARC_TLS_LDM_LO10 = 61, ++ R_SPARC_TLS_LDM_ADD = 62, ++ R_SPARC_TLS_LDM_CALL = 63, ++ R_SPARC_TLS_LDO_HIX22 = 64, ++ R_SPARC_TLS_LDO_LOX10 = 65, ++ R_SPARC_TLS_LDO_ADD = 66, ++ R_SPARC_TLS_IE_HI22 = 67, ++ R_SPARC_TLS_IE_LO10 = 68, ++ R_SPARC_TLS_IE_LD = 69, ++ R_SPARC_TLS_IE_LDX = 70, ++ R_SPARC_TLS_IE_ADD = 71, ++ R_SPARC_TLS_LE_HIX22 = 72, ++ R_SPARC_TLS_LE_LOX10 = 73, ++ R_SPARC_TLS_DTPMOD32 = 74, ++ R_SPARC_TLS_DTPMOD64 = 75, ++ R_SPARC_TLS_DTPOFF32 = 76, ++ R_SPARC_TLS_DTPOFF64 = 77, ++ R_SPARC_TLS_TPOFF32 = 78, ++ R_SPARC_TLS_TPOFF64 = 79, ++ R_SPARC_GOTDATA_HIX22 = 80, ++ R_SPARC_GOTDATA_LOX22 = 81, ++ R_SPARC_GOTDATA_OP_HIX22 = 82, ++ R_SPARC_GOTDATA_OP_LOX22 = 83, ++ R_SPARC_GOTDATA_OP = 84 + }; + + // Section header. diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200104-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200104-sparc.diff new file mode 100644 index 0000000..c489ca1 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200104-sparc.diff @@ -0,0 +1,18 @@ +Pull in r200104 from upstream llvm trunk (by Venkatraman Govindaraju): + + removing duplicate enum value + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: include/llvm/Support/ELF.h +=================================================================== +--- include/llvm/Support/ELF.h ++++ include/llvm/Support/ELF.h +@@ -1144,7 +1144,6 @@ enum { + R_SPARC_REGISTER = 53, + R_SPARC_UA64 = 54, + R_SPARC_UA16 = 55, +- R_SPARC_UA16 = 55, + R_SPARC_TLS_GD_HI22 = 56, + R_SPARC_TLS_GD_LO10 = 57, + R_SPARC_TLS_GD_ADD = 58, diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200112-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200112-sparc.diff new file mode 100644 index 0000000..f499b59 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200112-sparc.diff @@ -0,0 +1,169 @@ +Pull in r200112 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add support for sparc relocation types in ELF object file. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/MC/Sparc/sparc-relocations.s +=================================================================== +--- test/MC/Sparc/sparc-relocations.s ++++ test/MC/Sparc/sparc-relocations.s +@@ -1,5 +1,18 @@ + ! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s ++! RUN: llvm-mc %s -arch=sparcv9 -filetype=obj | llvm-readobj -r | FileCheck %s --check-prefix=CHECK-OBJ + ++ ! CHECK-OBJ: Format: ELF64-sparc ++ ! CHECK-OBJ: Relocations [ ++ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_WDISP30 foo ++ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_LO10 sym ++ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HI22 sym ++ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_H44 sym ++ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_M44 sym ++ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_L44 sym ++ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HH22 sym ++ ! CHECK-OBJ: 0x{{[0-9,A-F]+}} R_SPARC_HM10 sym ++ ! CHECK-ELF: ] ++ + ! CHECK: call foo ! encoding: [0b01AAAAAA,A,A,A] + ! CHECK: ! fixup A - offset: 0, value: foo, kind: fixup_sparc_call30 + call foo +Index: include/llvm/Object/ELFObjectFile.h +=================================================================== +--- include/llvm/Object/ELFObjectFile.h ++++ include/llvm/Object/ELFObjectFile.h +@@ -922,6 +922,9 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() + return "ELF32-mips"; + case ELF::EM_PPC: + return "ELF32-ppc"; ++ case ELF::EM_SPARC: ++ case ELF::EM_SPARC32PLUS: ++ return "ELF32-sparc"; + default: + return "ELF32-unknown"; + } +@@ -937,6 +940,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() + return "ELF64-ppc64"; + case ELF::EM_S390: + return "ELF64-s390"; ++ case ELF::EM_SPARCV9: ++ return "ELF64-sparc"; + default: + return "ELF64-unknown"; + } +@@ -967,6 +972,13 @@ unsigned ELFObjectFile<ELFT>::getArch() const { + : Triple::ppc64; + case ELF::EM_S390: + return Triple::systemz; ++ ++ case ELF::EM_SPARC: ++ case ELF::EM_SPARC32PLUS: ++ return Triple::sparc; ++ case ELF::EM_SPARCV9: ++ return Triple::sparcv9; ++ + default: + return Triple::UnknownArch; + } +Index: lib/Object/ELF.cpp +=================================================================== +--- lib/Object/ELF.cpp ++++ lib/Object/ELF.cpp +@@ -702,6 +702,98 @@ StringRef getELFRelocationTypeName(uint32_t Machin + break; + } + break; ++ case ELF::EM_SPARC: ++ case ELF::EM_SPARC32PLUS: ++ case ELF::EM_SPARCV9: ++ switch (Type) { ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_NONE); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_8); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_16); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_32); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP8); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP16); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP32); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP30); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HI22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_13); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LO10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOT10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOT13); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOT22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WPLT30); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_COPY); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GLOB_DAT); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_JMP_SLOT); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_RELATIVE); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_UA32); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PLT32); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HIPLT22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LOPLT10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PCPLT32); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PCPLT22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PCPLT10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_11); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_64); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_OLO10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HH22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HM10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LM22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC_HH22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC_HM10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC_LM22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP16); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP19); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_7); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_5); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_6); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP64); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PLT64); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HIX22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LOX10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_H44); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_M44); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_L44); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_REGISTER); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_UA64); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_UA16); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_HI22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_LO10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_ADD); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_CALL); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_HI22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_LO10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_ADD); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_CALL); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDO_HIX22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDO_LOX10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDO_ADD); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_HI22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_LO10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_LD); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_LDX); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_ADD); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LE_HIX22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LE_LOX10); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPMOD32); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPMOD64); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPOFF32); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPOFF64); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_TPOFF32); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_TPOFF64); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_HIX22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_LOX22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_OP_HIX22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_OP_LOX22); ++ LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_OP); ++ default: ++ break; ++ } ++ break; + default: + break; + } diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200130-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200130-sparc.diff new file mode 100644 index 0000000..aad6ae9 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200130-sparc.diff @@ -0,0 +1,45 @@ +Pull in r200130 from upstream llvm trunk (by Jakob Stoklund Olesen): + + Fix swapped CASA operands. + + Found by SingleSource/UnitTests/AtomicOps.c + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -2972,7 +2972,7 @@ SparcTargetLowering::expandAtomicRMW(MachineInstr + // loop: + // %val = phi %val0, %dest + // %upd = op %val, %rs2 +- // %dest = cas %addr, %upd, %val ++ // %dest = cas %addr, %val, %upd + // cmp %val, %dest + // bne loop + // done: +@@ -3031,7 +3031,7 @@ SparcTargetLowering::expandAtomicRMW(MachineInstr + } + + BuildMI(LoopMBB, DL, TII.get(is64Bit ? SP::CASXrr : SP::CASrr), DestReg) +- .addReg(AddrReg).addReg(UpdReg).addReg(ValReg) ++ .addReg(AddrReg).addReg(ValReg).addReg(UpdReg) + .setMemRefs(MI->memoperands_begin(), MI->memoperands_end()); + BuildMI(LoopMBB, DL, TII.get(SP::CMPrr)).addReg(ValReg).addReg(DestReg); + BuildMI(LoopMBB, DL, TII.get(is64Bit ? SP::BPXCC : SP::BCOND)) +Index: test/CodeGen/SPARC/atomics.ll +=================================================================== +--- test/CodeGen/SPARC/atomics.ll ++++ test/CodeGen/SPARC/atomics.ll +@@ -64,8 +64,8 @@ entry: + + ; CHECK-LABEL: test_load_add_32 + ; CHECK: membar +-; CHECK: add +-; CHECK: cas [%o0] ++; CHECK: add [[V:%[gilo][0-7]]], %o1, [[U:%[gilo][0-7]]] ++; CHECK: cas [%o0], [[V]], [[U]] + ; CHECK: membar + define zeroext i32 @test_load_add_32(i32* %p, i32 zeroext %v) { + entry: diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200131-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200131-sparc.diff new file mode 100644 index 0000000..6b0ab16 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200131-sparc.diff @@ -0,0 +1,117 @@ +Pull in r200131 from upstream llvm trunk (by Jakob Stoklund Olesen): + + Only generate the popc instruction for SPARC CPUs that implement it. + + The popc instruction is defined in the SPARCv9 instruction set + architecture, but it was emulated on CPUs older than Niagara 2. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -1461,7 +1461,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMac + setOperationAction(ISD::BR_CC, MVT::i64, Custom); + setOperationAction(ISD::SELECT_CC, MVT::i64, Custom); + +- setOperationAction(ISD::CTPOP, MVT::i64, Legal); ++ if (Subtarget->usePopc()) ++ setOperationAction(ISD::CTPOP, MVT::i64, Legal); + setOperationAction(ISD::CTTZ , MVT::i64, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Expand); + setOperationAction(ISD::CTLZ , MVT::i64, Expand); +@@ -1567,7 +1568,7 @@ SparcTargetLowering::SparcTargetLowering(TargetMac + + setStackPointerRegisterToSaveRestore(SP::O6); + +- if (Subtarget->isV9()) ++ if (Subtarget->isV9() && Subtarget->usePopc()) + setOperationAction(ISD::CTPOP, MVT::i32, Legal); + + if (Subtarget->isV9() && Subtarget->hasHardQuad()) { +Index: lib/Target/Sparc/Sparc.td +=================================================================== +--- lib/Target/Sparc/Sparc.td ++++ lib/Target/Sparc/Sparc.td +@@ -34,6 +34,9 @@ def FeatureHardQuad + : SubtargetFeature<"hard-quad-float", "HasHardQuad", "true", + "Enable quad-word floating point instructions">; + ++def UsePopc : SubtargetFeature<"popc", "UsePopc", "true", ++ "Use the popc (population count) instruction">; ++ + //===----------------------------------------------------------------------===// + // Register File, Calling Conv, Instruction Descriptions + //===----------------------------------------------------------------------===// +@@ -69,9 +72,9 @@ def : Proc<"v9", [FeatureV9]>; + def : Proc<"ultrasparc", [FeatureV9, FeatureV8Deprecated]>; + def : Proc<"ultrasparc3", [FeatureV9, FeatureV8Deprecated]>; + def : Proc<"niagara", [FeatureV9, FeatureV8Deprecated]>; +-def : Proc<"niagara2", [FeatureV9, FeatureV8Deprecated]>; +-def : Proc<"niagara3", [FeatureV9, FeatureV8Deprecated]>; +-def : Proc<"niagara4", [FeatureV9, FeatureV8Deprecated]>; ++def : Proc<"niagara2", [FeatureV9, FeatureV8Deprecated, UsePopc]>; ++def : Proc<"niagara3", [FeatureV9, FeatureV8Deprecated, UsePopc]>; ++def : Proc<"niagara4", [FeatureV9, FeatureV8Deprecated, UsePopc]>; + + def SparcAsmWriter : AsmWriter { + string AsmWriterClassName = "InstPrinter"; +Index: lib/Target/Sparc/SparcSubtarget.h +=================================================================== +--- lib/Target/Sparc/SparcSubtarget.h ++++ lib/Target/Sparc/SparcSubtarget.h +@@ -30,6 +30,7 @@ class SparcSubtarget : public SparcGenSubtargetInf + bool IsVIS; + bool Is64Bit; + bool HasHardQuad; ++ bool UsePopc; + + public: + SparcSubtarget(const std::string &TT, const std::string &CPU, +@@ -39,6 +40,7 @@ class SparcSubtarget : public SparcGenSubtargetInf + bool isVIS() const { return IsVIS; } + bool useDeprecatedV8Instructions() const { return V8DeprecatedInsts; } + bool hasHardQuad() const { return HasHardQuad; } ++ bool usePopc() const { return UsePopc; } + + /// ParseSubtargetFeatures - Parses features string setting specified + /// subtarget options. Definition of function is auto generated by tblgen. +Index: lib/Target/Sparc/SparcSubtarget.cpp +=================================================================== +--- lib/Target/Sparc/SparcSubtarget.cpp ++++ lib/Target/Sparc/SparcSubtarget.cpp +@@ -31,7 +31,8 @@ SparcSubtarget::SparcSubtarget(const std::string & + V8DeprecatedInsts(false), + IsVIS(false), + Is64Bit(is64Bit), +- HasHardQuad(false) { ++ HasHardQuad(false), ++ UsePopc(false) { + + // Determine default and user specified characteristics + std::string CPUName = CPU; +Index: test/CodeGen/SPARC/ctpop.ll +=================================================================== +--- test/CodeGen/SPARC/ctpop.ll ++++ test/CodeGen/SPARC/ctpop.ll +@@ -1,13 +1,13 @@ + ; RUN: llc < %s -march=sparc -mattr=-v9 | FileCheck %s -check-prefix=V8 +-; RUN: llc < %s -march=sparc -mattr=+v9 | FileCheck %s -check-prefix=V9 +-; RUN: llc < %s -march=sparc -mcpu=v9 | FileCheck %s -check-prefix=V9 +-; RUN: llc < %s -march=sparc -mcpu=ultrasparc | FileCheck %s -check-prefix=V9 +-; RUN: llc < %s -march=sparc -mcpu=ultrasparc3 | FileCheck %s -check-prefix=V9 +-; RUN: llc < %s -march=sparc -mcpu=niagara | FileCheck %s -check-prefix=V9 ++; RUN: llc < %s -march=sparc -mattr=+v9,+popc | FileCheck %s -check-prefix=V9 ++; RUN: llc < %s -march=sparc -mcpu=v9 | FileCheck %s -check-prefix=V8 ++; RUN: llc < %s -march=sparc -mcpu=ultrasparc | FileCheck %s -check-prefix=V8 ++; RUN: llc < %s -march=sparc -mcpu=ultrasparc3 | FileCheck %s -check-prefix=V8 ++; RUN: llc < %s -march=sparc -mcpu=niagara | FileCheck %s -check-prefix=V8 + ; RUN: llc < %s -march=sparc -mcpu=niagara2 | FileCheck %s -check-prefix=V9 + ; RUN: llc < %s -march=sparc -mcpu=niagara3 | FileCheck %s -check-prefix=V9 + ; RUN: llc < %s -march=sparc -mcpu=niagara4 | FileCheck %s -check-prefix=V9 +-; RUN: llc < %s -march=sparcv9 | FileCheck %s -check-prefix=SPARC64 ++; RUN: llc < %s -march=sparcv9 -mattr=+popc | FileCheck %s -check-prefix=SPARC64 + + declare i32 @llvm.ctpop.i32(i32) + diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200141-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200141-sparc.diff new file mode 100644 index 0000000..d8016e8 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200141-sparc.diff @@ -0,0 +1,67 @@ +Pull in r200141 from upstream llvm trunk (by Jakob Stoklund Olesen): + + Clean up the Legal/Expand logic for SPARC popc. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcSubtarget.cpp +=================================================================== +--- lib/Target/Sparc/SparcSubtarget.cpp ++++ lib/Target/Sparc/SparcSubtarget.cpp +@@ -41,6 +41,10 @@ SparcSubtarget::SparcSubtarget(const std::string & + + // Parse features string. + ParseSubtargetFeatures(CPUName, FS); ++ ++ // Popc is a v9-only instruction. ++ if (!IsV9) ++ UsePopc = false; + } + + +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -1461,8 +1461,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMac + setOperationAction(ISD::BR_CC, MVT::i64, Custom); + setOperationAction(ISD::SELECT_CC, MVT::i64, Custom); + +- if (Subtarget->usePopc()) +- setOperationAction(ISD::CTPOP, MVT::i64, Legal); ++ setOperationAction(ISD::CTPOP, MVT::i64, ++ Subtarget->usePopc() ? Legal : Expand); + setOperationAction(ISD::CTTZ , MVT::i64, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Expand); + setOperationAction(ISD::CTLZ , MVT::i64, Expand); +@@ -1518,7 +1518,6 @@ SparcTargetLowering::SparcTargetLowering(TargetMac + setOperationAction(ISD::FSINCOS, MVT::f32, Expand); + setOperationAction(ISD::FREM , MVT::f32, Expand); + setOperationAction(ISD::FMA , MVT::f32, Expand); +- setOperationAction(ISD::CTPOP, MVT::i32, Expand); + setOperationAction(ISD::CTTZ , MVT::i32, Expand); + setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand); + setOperationAction(ISD::CTLZ , MVT::i32, Expand); +@@ -1568,8 +1567,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMac + + setStackPointerRegisterToSaveRestore(SP::O6); + +- if (Subtarget->isV9() && Subtarget->usePopc()) +- setOperationAction(ISD::CTPOP, MVT::i32, Legal); ++ setOperationAction(ISD::CTPOP, MVT::i32, ++ Subtarget->usePopc() ? Legal : Expand); + + if (Subtarget->isV9() && Subtarget->hasHardQuad()) { + setOperationAction(ISD::LOAD, MVT::f128, Legal); +Index: test/CodeGen/SPARC/64bit.ll +=================================================================== +--- test/CodeGen/SPARC/64bit.ll ++++ test/CodeGen/SPARC/64bit.ll +@@ -1,5 +1,5 @@ +-; RUN: llc < %s -march=sparcv9 -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s +-; RUN: llc < %s -march=sparcv9 | FileCheck %s -check-prefix=OPT ++; RUN: llc < %s -march=sparcv9 -mattr=+popc -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s ++; RUN: llc < %s -march=sparcv9 -mattr=+popc | FileCheck %s -check-prefix=OPT + + ; CHECK-LABEL: ret2: + ; CHECK: or %g0, %i1, %i0 diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200282-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200282-sparc.diff new file mode 100644 index 0000000..95f2868 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200282-sparc.diff @@ -0,0 +1,183 @@ +Pull in r200282 from upstream llvm trunk (by Jakob Stoklund Olesen): + + Fix the DWARF EH encodings for Sparc PIC code. + + Also emit the stubs that were generated for references to typeinfo + symbols. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcAsmPrinter.cpp +=================================================================== +--- lib/Target/Sparc/SparcAsmPrinter.cpp ++++ lib/Target/Sparc/SparcAsmPrinter.cpp +@@ -23,7 +23,9 @@ + #include "llvm/ADT/SmallString.h" + #include "llvm/CodeGen/AsmPrinter.h" + #include "llvm/CodeGen/MachineInstr.h" ++#include "llvm/CodeGen/MachineModuleInfoImpls.h" + #include "llvm/CodeGen/MachineRegisterInfo.h" ++#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" + #include "llvm/MC/MCAsmInfo.h" + #include "llvm/MC/MCContext.h" + #include "llvm/MC/MCInst.h" +@@ -54,6 +56,7 @@ namespace { + + virtual void EmitFunctionBodyStart(); + virtual void EmitInstruction(const MachineInstr *MI); ++ virtual void EmitEndOfAsmFile(Module &M); + + static const char *getRegisterName(unsigned RegNo) { + return SparcInstPrinter::getRegisterName(RegNo); +@@ -450,6 +453,23 @@ bool SparcAsmPrinter::PrintAsmMemoryOperand(const + return false; + } + ++void SparcAsmPrinter::EmitEndOfAsmFile(Module &M) { ++ const TargetLoweringObjectFileELF &TLOFELF = ++ static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering()); ++ MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>(); ++ ++ // Generate stubs for global variables. ++ MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList(); ++ if (!Stubs.empty()) { ++ OutStreamer.SwitchSection(TLOFELF.getDataSection()); ++ unsigned PtrSize = TM.getDataLayout()->getPointerSize(0); ++ for (unsigned i = 0, e = Stubs.size(); i != e; ++i) { ++ OutStreamer.EmitLabel(Stubs[i].first); ++ OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), PtrSize); ++ } ++ } ++} ++ + // Force static initialization. + extern "C" void LLVMInitializeSparcAsmPrinter() { + RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget); +Index: lib/MC/MCObjectFileInfo.cpp +=================================================================== +--- lib/MC/MCObjectFileInfo.cpp ++++ lib/MC/MCObjectFileInfo.cpp +@@ -310,6 +310,33 @@ void MCObjectFileInfo::InitELFMCObjectFileInfo(Tri + FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8; + TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_udata8; ++ } else if (T.getArch() == Triple::sparc) { ++ if (RelocM == Reloc::PIC_) { ++ LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; ++ PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | ++ dwarf::DW_EH_PE_sdata4; ++ FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; ++ TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | ++ dwarf::DW_EH_PE_sdata4; ++ } else { ++ LSDAEncoding = dwarf::DW_EH_PE_absptr; ++ PersonalityEncoding = dwarf::DW_EH_PE_absptr; ++ FDEEncoding = dwarf::DW_EH_PE_udata4; ++ TTypeEncoding = dwarf::DW_EH_PE_absptr; ++ } ++ } else if (T.getArch() == Triple::sparcv9) { ++ LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; ++ if (RelocM == Reloc::PIC_) { ++ PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | ++ dwarf::DW_EH_PE_sdata4; ++ FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; ++ TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | ++ dwarf::DW_EH_PE_sdata4; ++ } else { ++ PersonalityEncoding = dwarf::DW_EH_PE_absptr; ++ FDEEncoding = dwarf::DW_EH_PE_udata4; ++ TTypeEncoding = dwarf::DW_EH_PE_absptr; ++ } + } else if (T.getArch() == Triple::systemz) { + // All currently-defined code models guarantee that 4-byte PC-relative + // values will be in range. +Index: test/CodeGen/SPARC/exception.ll +=================================================================== +--- test/CodeGen/SPARC/exception.ll ++++ test/CodeGen/SPARC/exception.ll +@@ -1,4 +1,7 @@ +-; RUN: llc < %s -march=sparc | FileCheck %s ++; RUN: llc < %s -march=sparc -relocation-model=static | FileCheck -check-prefix=V8ABS %s ++; RUN: llc < %s -march=sparc -relocation-model=pic | FileCheck -check-prefix=V8PIC %s ++; RUN: llc < %s -march=sparcv9 -relocation-model=static | FileCheck -check-prefix=V9ABS %s ++; RUN: llc < %s -march=sparcv9 -relocation-model=pic | FileCheck -check-prefix=V9PIC %s + + + %struct.__fundamental_type_info_pseudo = type { %struct.__type_info_pseudo } +@@ -9,23 +12,64 @@ + @.cst = linker_private unnamed_addr constant [12 x i8] c"catched int\00", align 64 + @.cst1 = linker_private unnamed_addr constant [14 x i8] c"catched float\00", align 64 + +-; CHECK-LABEL: main: +-; CHECK: .cfi_startproc +-; CHECK: .cfi_def_cfa_register {{30|%fp}} +-; CHECK: .cfi_window_save +-; CHECK: .cfi_register 15, 31 ++; V8ABS-LABEL: main: ++; V8ABS: .cfi_startproc ++; V8ABS: .cfi_personality 0, __gxx_personality_v0 ++; V8ABS: .cfi_lsda 0, ++; V8ABS: .cfi_def_cfa_register {{30|%fp}} ++; V8ABS: .cfi_window_save ++; V8ABS: .cfi_register 15, 31 + +-; CHECK: call __cxa_throw +-; CHECK: call __cxa_throw ++; V8ABS: call __cxa_throw ++; V8ABS: call __cxa_throw + +-; CHECK: call __cxa_begin_catch +-; CHECK: call __cxa_end_catch ++; V8ABS: call __cxa_begin_catch ++; V8ABS: call __cxa_end_catch + +-; CHECK: call __cxa_begin_catch +-; CHECK: call __cxa_end_catch ++; V8ABS: call __cxa_begin_catch ++; V8ABS: call __cxa_end_catch + +-; CHECK: .cfi_endproc ++; V8ABS: .cfi_endproc + ++; V8PIC-LABEL: main: ++; V8PIC: .cfi_startproc ++; V8PIC: .cfi_personality 155, DW.ref.__gxx_personality_v0 ++; V8PIC: .cfi_lsda 27, ++; V8PIC: .cfi_def_cfa_register {{30|%fp}} ++; V8PIC: .cfi_window_save ++; V8PIC: .cfi_register 15, 31 ++; V8PIC: .section .gcc_except_table ++; V8PIC-NOT: .section ++; V8PIC: .word .L_ZTIi.DW.stub- ++; V8PIC: .data ++; V8PIC: .L_ZTIi.DW.stub: ++; V8PIC-NEXT: .word _ZTIi ++ ++; V9ABS-LABEL: main: ++; V9ABS: .cfi_startproc ++; V9ABS: .cfi_personality 0, __gxx_personality_v0 ++; V9ABS: .cfi_lsda 27, ++; V9ABS: .cfi_def_cfa_register {{30|%fp}} ++; V9ABS: .cfi_window_save ++; V9ABS: .cfi_register 15, 31 ++; V9ABS: .section .gcc_except_table ++; V9ABS-NOT: .section ++; V9ABS: .xword _ZTIi ++ ++; V9PIC-LABEL: main: ++; V9PIC: .cfi_startproc ++; V9PIC: .cfi_personality 155, DW.ref.__gxx_personality_v0 ++; V9PIC: .cfi_lsda 27, ++; V9PIC: .cfi_def_cfa_register {{30|%fp}} ++; V9PIC: .cfi_window_save ++; V9PIC: .cfi_register 15, 31 ++; V9PIC: .section .gcc_except_table ++; V9PIC-NOT: .section ++; V9PIC: .word .L_ZTIi.DW.stub- ++; V9PIC: .data ++; V9PIC: .L_ZTIi.DW.stub: ++; V9PIC-NEXT: .xword _ZTIi ++ + define i32 @main(i32 %argc, i8** nocapture readnone %argv) unnamed_addr #0 { + entry: + %0 = icmp eq i32 %argc, 2 diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200368-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200368-sparc.diff new file mode 100644 index 0000000..f596b5f --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200368-sparc.diff @@ -0,0 +1,88 @@ +Pull r200368 from upstream llvm trunk (by Venkatraman Govindaraju): + + [SparcV9] Use correct register class (I64RegClass) to hold the address of _GLOBAL_OFFSET_TABLE_ in sparcv9. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcInstrInfo.cpp +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.cpp ++++ lib/Target/Sparc/SparcInstrInfo.cpp +@@ -431,9 +431,10 @@ unsigned SparcInstrInfo::getGlobalBaseReg(MachineF + MachineBasicBlock::iterator MBBI = FirstMBB.begin(); + MachineRegisterInfo &RegInfo = MF->getRegInfo(); + +- GlobalBaseReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass); ++ const TargetRegisterClass *PtrRC = ++ Subtarget.is64Bit() ? &SP::I64RegsRegClass : &SP::IntRegsRegClass; ++ GlobalBaseReg = RegInfo.createVirtualRegister(PtrRC); + +- + DebugLoc dl; + + BuildMI(FirstMBB, MBBI, dl, get(SP::GETPCX), GlobalBaseReg); +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -180,7 +180,7 @@ def tlscall : SDNode<"SPISD::TLS_CALL", SDT_ + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; + +-def getPCX : Operand<i32> { ++def getPCX : Operand<iPTR> { + let PrintMethod = "printGetPCX"; + } + +Index: test/CodeGen/SPARC/2009-08-28-PIC.ll +=================================================================== +--- test/CodeGen/SPARC/2009-08-28-PIC.ll ++++ test/CodeGen/SPARC/2009-08-28-PIC.ll +@@ -1,9 +1,45 @@ +-; RUN: llc -march=sparc --relocation-model=pic < %s | grep _GLOBAL_OFFSET_TABLE_ ++; RUN: llc -march=sparc --relocation-model=pic < %s | FileCheck %s --check-prefix=V8 ++; RUN: llc -march=sparcv9 --relocation-model=pic < %s | FileCheck %s --check-prefix=V9 ++; RUN: llc -march=sparc --relocation-model=pic < %s -O0 | FileCheck %s --check-prefix=V8UNOPT ++; RUN: llc -march=sparcv9 --relocation-model=pic < %s -O0 | FileCheck %s --check-prefix=V9UNOPT + ++ ++; V8-LABEL: func ++; V8: _GLOBAL_OFFSET_TABLE_ ++ ++; V9-LABEL: func ++; V9: _GLOBAL_OFFSET_TABLE_ ++ + @foo = global i32 0 ; <i32*> [#uses=1] + +-define i32 @func() nounwind readonly { ++define i32 @func(i32 %a) nounwind readonly { + entry: + %0 = load i32* @foo, align 4 ; <i32> [#uses=1] + ret i32 %0 + } ++ ++; V8UNOPT-LABEL: test_spill ++; V8UNOPT: sethi %hi(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[R:%[goli][0-7]]] ++; V8UNOPT: or [[R]], %lo(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[R]] ++; V8UNOPT: add [[R]], %o7, [[R]] ++; V8UNOPT: st [[R]], [%fp+{{.+}}] ++ ++; V9UNOPT-LABEL: test_spill ++; V9UNOPT: sethi %hi(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[R:%[goli][0-7]]] ++; V9UNOPT: or [[R]], %lo(_GLOBAL_OFFSET_TABLE_+{{.+}}), [[R]] ++; V9UNOPT: add [[R]], %o7, [[R]] ++; V9UNOPT: stx [[R]], [%fp+{{.+}}] ++ ++define i32 @test_spill(i32 %a, i32 %b) { ++entry: ++ %cmp = icmp eq i32 %b, 0 ++ br i1 %cmp, label %if.then, label %if.end ++ ++if.then: ++ %ret = load i32* @foo, align 4 ++ ret i32 %ret ++ ++if.end: ++ %add = add nsw i32 %b, %a ++ ret i32 %add ++} diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200373-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200373-sparc.diff new file mode 100644 index 0000000..f9bed35 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200373-sparc.diff @@ -0,0 +1,296 @@ +Pull in r200373 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Use %r_disp32 for pc_rel entries in gcc_except_table and eh_frame. + + Otherwise, assembler (gas) fails to assemble them with error message "operation + combines symbols in different segments". This is because MC computes + pc_rel entries with subtract expression between labels from different sections. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcTargetObjectFile.h +=================================================================== +--- lib/Target/Sparc/SparcTargetObjectFile.h ++++ lib/Target/Sparc/SparcTargetObjectFile.h +@@ -0,0 +1,34 @@ ++//===-- SparcTargetObjectFile.h - Sparc Object Info -------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#ifndef LLVM_TARGET_SPARC_TARGETOBJECTFILE_H ++#define LLVM_TARGET_SPARC_TARGETOBJECTFILE_H ++ ++#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" ++ ++namespace llvm { ++ ++class MCContext; ++class TargetMachine; ++ ++class SparcELFTargetObjectFile : public TargetLoweringObjectFileELF { ++public: ++ SparcELFTargetObjectFile() : ++ TargetLoweringObjectFileELF() ++ {} ++ ++ const MCExpr * ++ getTTypeGlobalReference(const GlobalValue *GV, Mangler *Mang, ++ MachineModuleInfo *MMI, unsigned Encoding, ++ MCStreamer &Streamer) const; ++}; ++ ++} // end namespace llvm ++ ++#endif +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -16,6 +16,7 @@ + #include "SparcMachineFunctionInfo.h" + #include "SparcRegisterInfo.h" + #include "SparcTargetMachine.h" ++#include "SparcTargetObjectFile.h" + #include "MCTargetDesc/SparcBaseInfo.h" + #include "llvm/CodeGen/CallingConvLower.h" + #include "llvm/CodeGen/MachineFrameInfo.h" +@@ -1361,7 +1362,7 @@ static SPCC::CondCodes FPCondCCodeToFCC(ISD::CondC + } + + SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) +- : TargetLowering(TM, new TargetLoweringObjectFileELF()) { ++ : TargetLowering(TM, new SparcELFTargetObjectFile()) { + Subtarget = &TM.getSubtarget<SparcSubtarget>(); + + // Set up the register classes. +Index: lib/Target/Sparc/SparcTargetObjectFile.cpp +=================================================================== +--- lib/Target/Sparc/SparcTargetObjectFile.cpp ++++ lib/Target/Sparc/SparcTargetObjectFile.cpp +@@ -0,0 +1,48 @@ ++//===------- SparcTargetObjectFile.cpp - Sparc Object Info Impl -----------===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++ ++#include "SparcTargetObjectFile.h" ++#include "MCTargetDesc/SparcMCExpr.h" ++#include "llvm/CodeGen/MachineModuleInfoImpls.h" ++#include "llvm/Support/Dwarf.h" ++#include "llvm/Target/Mangler.h" ++ ++using namespace llvm; ++ ++ ++const MCExpr *SparcELFTargetObjectFile:: ++getTTypeGlobalReference(const GlobalValue *GV, Mangler *Mang, ++ MachineModuleInfo *MMI, unsigned Encoding, ++ MCStreamer &Streamer) const { ++ ++ if (Encoding & dwarf::DW_EH_PE_pcrel) { ++ MachineModuleInfoELF &ELFMMI = MMI->getObjFileInfo<MachineModuleInfoELF>(); ++ ++ //MCSymbol *SSym = getSymbolWithGlobalValueBase(*Mang, GV, ".DW.stub"); ++ SmallString<60> NameStr; ++ Mang->getNameWithPrefix(NameStr, GV, true); ++ NameStr.append(".DW.stub"); ++ MCSymbol *SSym = getContext().GetOrCreateSymbol(NameStr.str()); ++ ++ // Add information about the stub reference to ELFMMI so that the stub ++ // gets emitted by the asmprinter. ++ MachineModuleInfoImpl::StubValueTy &StubSym = ELFMMI.getGVStubEntry(SSym); ++ if (StubSym.getPointer() == 0) { ++ MCSymbol *Sym = getSymbol(*Mang, GV); ++ StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage()); ++ } ++ ++ MCContext &Ctx = getContext(); ++ return SparcMCExpr::Create(SparcMCExpr::VK_Sparc_R_DISP32, ++ MCSymbolRefExpr::Create(SSym, Ctx), Ctx); ++ } ++ ++ return TargetLoweringObjectFileELF:: ++ getTTypeGlobalReference(GV, Mang, MMI, Encoding, Streamer); ++} +Index: lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp +@@ -12,7 +12,9 @@ + //===----------------------------------------------------------------------===// + + #include "SparcMCAsmInfo.h" ++#include "SparcMCExpr.h" + #include "llvm/ADT/Triple.h" ++#include "llvm/MC/MCStreamer.h" + + using namespace llvm; + +@@ -44,4 +46,15 @@ SparcELFMCAsmInfo::SparcELFMCAsmInfo(StringRef TT) + PrivateGlobalPrefix = ".L"; + } + ++const MCExpr* ++SparcELFMCAsmInfo::getExprForPersonalitySymbol(const MCSymbol *Sym, ++ unsigned Encoding, ++ MCStreamer &Streamer) const { ++ if (Encoding & dwarf::DW_EH_PE_pcrel) { ++ MCContext &Ctx = Streamer.getContext(); ++ return SparcMCExpr::Create(SparcMCExpr::VK_Sparc_R_DISP32, ++ MCSymbolRefExpr::Create(Sym, Ctx), Ctx); ++ } + ++ return MCAsmInfo::getExprForPersonalitySymbol(Sym, Encoding, Streamer); ++} +Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +@@ -41,6 +41,7 @@ void SparcMCExpr::PrintImpl(raw_ostream &OS) const + case VK_Sparc_L44: OS << "%l44("; break; + case VK_Sparc_HH: OS << "%hh("; break; + case VK_Sparc_HM: OS << "%hm("; break; ++ case VK_Sparc_R_DISP32: OS << "%r_disp32("; break; + case VK_Sparc_TLS_GD_HI22: OS << "%tgd_hi22("; break; + case VK_Sparc_TLS_GD_LO10: OS << "%tgd_lo10("; break; + case VK_Sparc_TLS_GD_ADD: OS << "%tgd_add("; break; +@@ -77,6 +78,7 @@ SparcMCExpr::VariantKind SparcMCExpr::parseVariant + .Case("l44", VK_Sparc_L44) + .Case("hh", VK_Sparc_HH) + .Case("hm", VK_Sparc_HM) ++ .Case("r_disp32", VK_Sparc_R_DISP32) + .Case("tgd_hi22", VK_Sparc_TLS_GD_HI22) + .Case("tgd_lo10", VK_Sparc_TLS_GD_LO10) + .Case("tgd_add", VK_Sparc_TLS_GD_ADD) +@@ -101,6 +103,8 @@ SparcMCExpr::VariantKind SparcMCExpr::parseVariant + bool + SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout) const { ++ if (!Layout) ++ return false; + return getSubExpr()->EvaluateAsRelocatable(Res, *Layout); + } + +Index: lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h ++++ lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h +@@ -17,13 +17,16 @@ + #include "llvm/MC/MCAsmInfoELF.h" + + namespace llvm { +- class StringRef; ++class StringRef; + +- class SparcELFMCAsmInfo : public MCAsmInfoELF { +- virtual void anchor(); +- public: +- explicit SparcELFMCAsmInfo(StringRef TT); +- }; ++class SparcELFMCAsmInfo : public MCAsmInfoELF { ++ virtual void anchor(); ++public: ++ explicit SparcELFMCAsmInfo(StringRef TT); ++ virtual const MCExpr* getExprForPersonalitySymbol(const MCSymbol *Sym, ++ unsigned Encoding, ++ MCStreamer &Streamer) const; ++}; + + } // namespace llvm + +Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h ++++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h +@@ -31,6 +31,7 @@ class SparcMCExpr : public MCTargetExpr { + VK_Sparc_L44, + VK_Sparc_HH, + VK_Sparc_HM, ++ VK_Sparc_R_DISP32, + VK_Sparc_TLS_GD_HI22, + VK_Sparc_TLS_GD_LO10, + VK_Sparc_TLS_GD_ADD, +Index: lib/Target/Sparc/CMakeLists.txt +=================================================================== +--- lib/Target/Sparc/CMakeLists.txt ++++ lib/Target/Sparc/CMakeLists.txt +@@ -27,6 +27,7 @@ add_llvm_target(SparcCodeGen + SparcJITInfo.cpp + SparcCodeEmitter.cpp + SparcMCInstLower.cpp ++ SparcTargetObjectFile.cpp + ) + + add_dependencies(LLVMSparcCodeGen SparcCommonTableGen intrinsics_gen) +Index: test/CodeGen/SPARC/exception.ll +=================================================================== +--- test/CodeGen/SPARC/exception.ll ++++ test/CodeGen/SPARC/exception.ll +@@ -1,7 +1,9 @@ + ; RUN: llc < %s -march=sparc -relocation-model=static | FileCheck -check-prefix=V8ABS %s + ; RUN: llc < %s -march=sparc -relocation-model=pic | FileCheck -check-prefix=V8PIC %s ++; RUN: llc < %s -march=sparc -relocation-model=pic -disable-cfi | FileCheck -check-prefix=V8PIC_NOCFI %s + ; RUN: llc < %s -march=sparcv9 -relocation-model=static | FileCheck -check-prefix=V9ABS %s + ; RUN: llc < %s -march=sparcv9 -relocation-model=pic | FileCheck -check-prefix=V9PIC %s ++; RUN: llc < %s -march=sparcv9 -relocation-model=pic -disable-cfi | FileCheck -check-prefix=V9PIC_NOCFI %s + + + %struct.__fundamental_type_info_pseudo = type { %struct.__type_info_pseudo } +@@ -40,11 +42,23 @@ + ; V8PIC: .cfi_register 15, 31 + ; V8PIC: .section .gcc_except_table + ; V8PIC-NOT: .section +-; V8PIC: .word .L_ZTIi.DW.stub- ++; V8PIC: .word %r_disp32(.L_ZTIi.DW.stub) + ; V8PIC: .data + ; V8PIC: .L_ZTIi.DW.stub: + ; V8PIC-NEXT: .word _ZTIi + ++; V8PIC_NOCFI-LABEL: main: ++; V8PIC_NOCFI: .section .gcc_except_table ++; V8PIC_NOCFI-NOT: .section ++; V8PIC_NOCFI: .word %r_disp32(.L_ZTIi.DW.stub) ++; V8PIC_NOCFI: .data ++; V8PIC_NOCFI: .L_ZTIi.DW.stub: ++; V8PIC_NOCFI-NEXT: .word _ZTIi ++; V8PIC_NOCFI: .section .eh_frame ++; V8PIC_NOCFI-NOT: .section ++; V8PIC_NOCFI: .word %r_disp32(DW.ref.__gxx_personality_v0) ++ ++ + ; V9ABS-LABEL: main: + ; V9ABS: .cfi_startproc + ; V9ABS: .cfi_personality 0, __gxx_personality_v0 +@@ -65,11 +79,22 @@ + ; V9PIC: .cfi_register 15, 31 + ; V9PIC: .section .gcc_except_table + ; V9PIC-NOT: .section +-; V9PIC: .word .L_ZTIi.DW.stub- ++; V9PIC: .word %r_disp32(.L_ZTIi.DW.stub) + ; V9PIC: .data + ; V9PIC: .L_ZTIi.DW.stub: + ; V9PIC-NEXT: .xword _ZTIi + ++; V9PIC_NOCFI-LABEL: main: ++; V9PIC_NOCFI: .section .gcc_except_table ++; V9PIC_NOCFI-NOT: .section ++; V9PIC_NOCFI: .word %r_disp32(.L_ZTIi.DW.stub) ++; V9PIC_NOCFI: .data ++; V9PIC_NOCFI: .L_ZTIi.DW.stub: ++; V9PIC_NOCFI-NEXT: .xword _ZTIi ++; V9PIC_NOCFI: .section .eh_frame ++; V9PIC_NOCFI-NOT: .section ++; V9PIC_NOCFI: .word %r_disp32(DW.ref.__gxx_personality_v0) ++ + define i32 @main(i32 %argc, i8** nocapture readnone %argv) unnamed_addr #0 { + entry: + %0 = icmp eq i32 %argc, 2 diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200376-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200376-sparc.diff new file mode 100644 index 0000000..0053365 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200376-sparc.diff @@ -0,0 +1,76 @@ +Pull in r200376 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Use %r_disp32 for pc_rel entries in FDE as well. + + This makes MCAsmInfo::getExprForFDESymbol() a virtual function and overrides it in SparcMCAsmInfo. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h ++++ lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h +@@ -26,6 +26,10 @@ class SparcELFMCAsmInfo : public MCAsmInfoELF { + virtual const MCExpr* getExprForPersonalitySymbol(const MCSymbol *Sym, + unsigned Encoding, + MCStreamer &Streamer) const; ++ virtual const MCExpr* getExprForFDESymbol(const MCSymbol *Sym, ++ unsigned Encoding, ++ MCStreamer &Streamer) const; ++ + }; + + } // namespace llvm +Index: lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp +@@ -58,3 +58,15 @@ SparcELFMCAsmInfo::getExprForPersonalitySymbol(con + + return MCAsmInfo::getExprForPersonalitySymbol(Sym, Encoding, Streamer); + } ++ ++const MCExpr* ++SparcELFMCAsmInfo::getExprForFDESymbol(const MCSymbol *Sym, ++ unsigned Encoding, ++ MCStreamer &Streamer) const { ++ if (Encoding & dwarf::DW_EH_PE_pcrel) { ++ MCContext &Ctx = Streamer.getContext(); ++ return SparcMCExpr::Create(SparcMCExpr::VK_Sparc_R_DISP32, ++ MCSymbolRefExpr::Create(Sym, Ctx), Ctx); ++ } ++ return MCAsmInfo::getExprForFDESymbol(Sym, Encoding, Streamer); ++} +Index: test/CodeGen/SPARC/exception.ll +=================================================================== +--- test/CodeGen/SPARC/exception.ll ++++ test/CodeGen/SPARC/exception.ll +@@ -57,6 +57,7 @@ + ; V8PIC_NOCFI: .section .eh_frame + ; V8PIC_NOCFI-NOT: .section + ; V8PIC_NOCFI: .word %r_disp32(DW.ref.__gxx_personality_v0) ++; V8PIC_NOCFI: .word %r_disp32(.Ltmp{{.+}}) ! FDE initial location + + + ; V9ABS-LABEL: main: +@@ -94,6 +95,7 @@ + ; V9PIC_NOCFI: .section .eh_frame + ; V9PIC_NOCFI-NOT: .section + ; V9PIC_NOCFI: .word %r_disp32(DW.ref.__gxx_personality_v0) ++; V9PIC_NOCFI: .word %r_disp32(.Ltmp{{.+}}) ! FDE initial location + + define i32 @main(i32 %argc, i8** nocapture readnone %argv) unnamed_addr #0 { + entry: +Index: include/llvm/MC/MCAsmInfo.h +=================================================================== +--- include/llvm/MC/MCAsmInfo.h ++++ include/llvm/MC/MCAsmInfo.h +@@ -371,7 +371,7 @@ namespace llvm { + unsigned Encoding, + MCStreamer &Streamer) const; + +- const MCExpr * ++ virtual const MCExpr * + getExprForFDESymbol(const MCSymbol *Sym, + unsigned Encoding, + MCStreamer &Streamer) const; diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200509-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200509-sparc.diff new file mode 100644 index 0000000..9ada6aa --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200509-sparc.diff @@ -0,0 +1,73 @@ +Pull in r200509 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Save and restore float registers that may be used for parameter passing. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcJITInfo.cpp +=================================================================== +--- lib/Target/Sparc/SparcJITInfo.cpp ++++ lib/Target/Sparc/SparcJITInfo.cpp +@@ -28,6 +28,13 @@ extern "C" void SparcCompilationCallback(); + + extern "C" { + #if defined (__sparc__) ++ ++#if defined(__arch64__) ++#define FRAME_PTR(X) #X "+2047" ++#else ++#define FRAME_PTR(X) #X ++#endif ++ + asm( + ".text\n" + "\t.align 4\n" +@@ -34,11 +41,46 @@ extern "C" { + "\t.global SparcCompilationCallback\n" + "\t.type SparcCompilationCallback, #function\n" + "SparcCompilationCallback:\n" +- // Save current register window. +- "\tsave %sp, -192, %sp\n" ++ // Save current register window and create stack. ++ // 128 (save area) + 6*8 (for arguments) + 16*8 (for float regfile) = 304 ++ "\tsave %sp, -304, %sp\n" ++ // save float regfile to the stack. ++ "\tstd %f0, [" FRAME_PTR(%fp) "-0]\n" ++ "\tstd %f2, [" FRAME_PTR(%fp) "-8]\n" ++ "\tstd %f4, [" FRAME_PTR(%fp) "-16]\n" ++ "\tstd %f6, [" FRAME_PTR(%fp) "-24]\n" ++ "\tstd %f8, [" FRAME_PTR(%fp) "-32]\n" ++ "\tstd %f10, [" FRAME_PTR(%fp) "-40]\n" ++ "\tstd %f12, [" FRAME_PTR(%fp) "-48]\n" ++ "\tstd %f14, [" FRAME_PTR(%fp) "-56]\n" ++ "\tstd %f16, [" FRAME_PTR(%fp) "-64]\n" ++ "\tstd %f18, [" FRAME_PTR(%fp) "-72]\n" ++ "\tstd %f20, [" FRAME_PTR(%fp) "-80]\n" ++ "\tstd %f22, [" FRAME_PTR(%fp) "-88]\n" ++ "\tstd %f24, [" FRAME_PTR(%fp) "-96]\n" ++ "\tstd %f26, [" FRAME_PTR(%fp) "-104]\n" ++ "\tstd %f28, [" FRAME_PTR(%fp) "-112]\n" ++ "\tstd %f30, [" FRAME_PTR(%fp) "-120]\n" + // stubaddr is in %g1. + "\tcall SparcCompilationCallbackC\n" + "\t mov %g1, %o0\n" ++ // restore float regfile from the stack. ++ "\tldd [" FRAME_PTR(%fp) "-0], %f0\n" ++ "\tldd [" FRAME_PTR(%fp) "-8], %f2\n" ++ "\tldd [" FRAME_PTR(%fp) "-16], %f4\n" ++ "\tldd [" FRAME_PTR(%fp) "-24], %f6\n" ++ "\tldd [" FRAME_PTR(%fp) "-32], %f8\n" ++ "\tldd [" FRAME_PTR(%fp) "-40], %f10\n" ++ "\tldd [" FRAME_PTR(%fp) "-48], %f12\n" ++ "\tldd [" FRAME_PTR(%fp) "-56], %f14\n" ++ "\tldd [" FRAME_PTR(%fp) "-64], %f16\n" ++ "\tldd [" FRAME_PTR(%fp) "-72], %f18\n" ++ "\tldd [" FRAME_PTR(%fp) "-80], %f20\n" ++ "\tldd [" FRAME_PTR(%fp) "-88], %f22\n" ++ "\tldd [" FRAME_PTR(%fp) "-96], %f24\n" ++ "\tldd [" FRAME_PTR(%fp) "-104], %f26\n" ++ "\tldd [" FRAME_PTR(%fp) "-112], %f28\n" ++ "\tldd [" FRAME_PTR(%fp) "-120], %f30\n" + // restore original register window and + // copy %o0 to %g1 + "\trestore %o0, 0, %g1\n" diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200617-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200617-sparc.diff new file mode 100644 index 0000000..831cd98 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200617-sparc.diff @@ -0,0 +1,97 @@ +Pull in r200617 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Set %o7 as the return address register instead of %i7 in MCRegisterInfo. Also, add CFI instructions to initialize the frame correctly. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +@@ -33,6 +33,25 @@ + + using namespace llvm; + ++ ++static MCAsmInfo *createSparcMCAsmInfo(const MCRegisterInfo &MRI, ++ StringRef TT) { ++ MCAsmInfo *MAI = new SparcELFMCAsmInfo(TT); ++ unsigned Reg = MRI.getDwarfRegNum(SP::O6, true); ++ MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(0, Reg, 0); ++ MAI->addInitialFrameState(Inst); ++ return MAI; ++} ++ ++static MCAsmInfo *createSparcV9MCAsmInfo(const MCRegisterInfo &MRI, ++ StringRef TT) { ++ MCAsmInfo *MAI = new SparcELFMCAsmInfo(TT); ++ unsigned Reg = MRI.getDwarfRegNum(SP::O6, true); ++ MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(0, Reg, 2047); ++ MAI->addInitialFrameState(Inst); ++ return MAI; ++} ++ + static MCInstrInfo *createSparcMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitSparcMCInstrInfo(X); +@@ -41,7 +60,7 @@ static MCInstrInfo *createSparcMCInstrInfo() { + + static MCRegisterInfo *createSparcMCRegisterInfo(StringRef TT) { + MCRegisterInfo *X = new MCRegisterInfo(); +- InitSparcMCRegisterInfo(X, SP::I7); ++ InitSparcMCRegisterInfo(X, SP::O7); + return X; + } + +@@ -132,8 +151,8 @@ static MCInstPrinter *createSparcMCInstPrinter(con + + extern "C" void LLVMInitializeSparcTargetMC() { + // Register the MC asm info. +- RegisterMCAsmInfo<SparcELFMCAsmInfo> X(TheSparcTarget); +- RegisterMCAsmInfo<SparcELFMCAsmInfo> Y(TheSparcV9Target); ++ RegisterMCAsmInfoFn X(TheSparcTarget, createSparcMCAsmInfo); ++ RegisterMCAsmInfoFn Y(TheSparcV9Target, createSparcV9MCAsmInfo); + + // Register the MC codegen info. + TargetRegistry::RegisterMCCodeGenInfo(TheSparcTarget, +Index: lib/Target/Sparc/SparcRegisterInfo.cpp +=================================================================== +--- lib/Target/Sparc/SparcRegisterInfo.cpp ++++ lib/Target/Sparc/SparcRegisterInfo.cpp +@@ -35,7 +35,7 @@ ReserveAppRegisters("sparc-reserve-app-registers", + cl::desc("Reserve application registers (%g2-%g4)")); + + SparcRegisterInfo::SparcRegisterInfo(SparcSubtarget &st) +- : SparcGenRegisterInfo(SP::I7), Subtarget(st) { ++ : SparcGenRegisterInfo(SP::O7), Subtarget(st) { + } + + const uint16_t* SparcRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) +Index: test/CodeGen/SPARC/exception.ll +=================================================================== +--- test/CodeGen/SPARC/exception.ll ++++ test/CodeGen/SPARC/exception.ll +@@ -56,7 +56,11 @@ + ; V8PIC_NOCFI-NEXT: .word _ZTIi + ; V8PIC_NOCFI: .section .eh_frame + ; V8PIC_NOCFI-NOT: .section ++; V8PIC_NOCFI: .byte 15 ! CIE Return Address Column + ; V8PIC_NOCFI: .word %r_disp32(DW.ref.__gxx_personality_v0) ++; V8PIC_NOCFI: .byte 12 ! DW_CFA_def_cfa ++; V8PIC_NOCFI: .byte 14 ! Reg 14 ++; V8PIC_NOCFI-NEXT: .byte 0 ! Offset 0 + ; V8PIC_NOCFI: .word %r_disp32(.Ltmp{{.+}}) ! FDE initial location + + +@@ -94,7 +98,11 @@ + ; V9PIC_NOCFI-NEXT: .xword _ZTIi + ; V9PIC_NOCFI: .section .eh_frame + ; V9PIC_NOCFI-NOT: .section ++; V9PIC_NOCFI: .byte 15 ! CIE Return Address Column + ; V9PIC_NOCFI: .word %r_disp32(DW.ref.__gxx_personality_v0) ++; V9PIC_NOCFI: .byte 12 ! DW_CFA_def_cfa ++; V9PIC_NOCFI-NEXT: .byte 14 ! Reg 14 ++; V9PIC_NOCFI: .ascii "\377\017" ! Offset 2047 + ; V9PIC_NOCFI: .word %r_disp32(.Ltmp{{.+}}) ! FDE initial location + + define i32 @main(i32 %argc, i8** nocapture readnone %argv) unnamed_addr #0 { diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200960-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200960-sparc.diff new file mode 100644 index 0000000..c430f88 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200960-sparc.diff @@ -0,0 +1,512 @@ +Pull in r200960 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Use SparcMCExpr::VariantKind itself as MachineOperand's target flags. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -13,11 +13,11 @@ + //===----------------------------------------------------------------------===// + + #include "SparcISelLowering.h" ++#include "MCTargetDesc/SparcMCExpr.h" + #include "SparcMachineFunctionInfo.h" + #include "SparcRegisterInfo.h" + #include "SparcTargetMachine.h" + #include "SparcTargetObjectFile.h" +-#include "MCTargetDesc/SparcBaseInfo.h" + #include "llvm/CodeGen/CallingConvLower.h" + #include "llvm/CodeGen/MachineFrameInfo.h" + #include "llvm/CodeGen/MachineFunction.h" +@@ -1796,7 +1796,8 @@ SDValue SparcTargetLowering::makeAddress(SDValue O + // Handle PIC mode first. + if (getTargetMachine().getRelocationModel() == Reloc::PIC_) { + // This is the pic32 code model, the GOT is known to be smaller than 4GB. +- SDValue HiLo = makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG); ++ SDValue HiLo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI, ++ SparcMCExpr::VK_Sparc_LO, DAG); + SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, VT); + SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, VT, GlobalBase, HiLo); + // GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this +@@ -1813,20 +1814,24 @@ SDValue SparcTargetLowering::makeAddress(SDValue O + llvm_unreachable("Unsupported absolute code model"); + case CodeModel::Small: + // abs32. +- return makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG); ++ return makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI, ++ SparcMCExpr::VK_Sparc_LO, DAG); + case CodeModel::Medium: { + // abs44. +- SDValue H44 = makeHiLoPair(Op, SPII::MO_H44, SPII::MO_M44, DAG); ++ SDValue H44 = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_H44, ++ SparcMCExpr::VK_Sparc_M44, DAG); + H44 = DAG.getNode(ISD::SHL, DL, VT, H44, DAG.getConstant(12, MVT::i32)); +- SDValue L44 = withTargetFlags(Op, SPII::MO_L44, DAG); ++ SDValue L44 = withTargetFlags(Op, SparcMCExpr::VK_Sparc_L44, DAG); + L44 = DAG.getNode(SPISD::Lo, DL, VT, L44); + return DAG.getNode(ISD::ADD, DL, VT, H44, L44); + } + case CodeModel::Large: { + // abs64. +- SDValue Hi = makeHiLoPair(Op, SPII::MO_HH, SPII::MO_HM, DAG); ++ SDValue Hi = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HH, ++ SparcMCExpr::VK_Sparc_HM, DAG); + Hi = DAG.getNode(ISD::SHL, DL, VT, Hi, DAG.getConstant(32, MVT::i32)); +- SDValue Lo = makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG); ++ SDValue Lo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI, ++ SparcMCExpr::VK_Sparc_LO, DAG); + return DAG.getNode(ISD::ADD, DL, VT, Hi, Lo); + } + } +@@ -1858,14 +1863,18 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress + TLSModel::Model model = getTargetMachine().getTLSModel(GV); + + if (model == TLSModel::GeneralDynamic || model == TLSModel::LocalDynamic) { +- unsigned HiTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_HI22 +- : SPII::MO_TLS_LDM_HI22); +- unsigned LoTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_LO10 +- : SPII::MO_TLS_LDM_LO10); +- unsigned addTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_ADD +- : SPII::MO_TLS_LDM_ADD); +- unsigned callTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_CALL +- : SPII::MO_TLS_LDM_CALL); ++ unsigned HiTF = ((model == TLSModel::GeneralDynamic) ++ ? SparcMCExpr::VK_Sparc_TLS_GD_HI22 ++ : SparcMCExpr::VK_Sparc_TLS_LDM_HI22); ++ unsigned LoTF = ((model == TLSModel::GeneralDynamic) ++ ? SparcMCExpr::VK_Sparc_TLS_GD_LO10 ++ : SparcMCExpr::VK_Sparc_TLS_LDM_LO10); ++ unsigned addTF = ((model == TLSModel::GeneralDynamic) ++ ? SparcMCExpr::VK_Sparc_TLS_GD_ADD ++ : SparcMCExpr::VK_Sparc_TLS_LDM_ADD); ++ unsigned callTF = ((model == TLSModel::GeneralDynamic) ++ ? SparcMCExpr::VK_Sparc_TLS_GD_CALL ++ : SparcMCExpr::VK_Sparc_TLS_LDM_CALL); + + SDValue HiLo = makeHiLoPair(Op, HiTF, LoTF, DAG); + SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT); +@@ -1903,17 +1912,17 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress + return Ret; + + SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT, +- withTargetFlags(Op, SPII::MO_TLS_LDO_HIX22, DAG)); ++ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_HIX22, DAG)); + SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT, +- withTargetFlags(Op, SPII::MO_TLS_LDO_LOX10, DAG)); ++ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_LOX10, DAG)); + HiLo = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo); + return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, Ret, HiLo, +- withTargetFlags(Op, SPII::MO_TLS_LDO_ADD, DAG)); ++ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_ADD, DAG)); + } + + if (model == TLSModel::InitialExec) { +- unsigned ldTF = ((PtrVT == MVT::i64)? SPII::MO_TLS_IE_LDX +- : SPII::MO_TLS_IE_LD); ++ unsigned ldTF = ((PtrVT == MVT::i64)? SparcMCExpr::VK_Sparc_TLS_IE_LDX ++ : SparcMCExpr::VK_Sparc_TLS_IE_LD); + + SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT); + +@@ -1923,7 +1932,8 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress + MFI->setHasCalls(true); + + SDValue TGA = makeHiLoPair(Op, +- SPII::MO_TLS_IE_HI22, SPII::MO_TLS_IE_LO10, DAG); ++ SparcMCExpr::VK_Sparc_TLS_IE_HI22, ++ SparcMCExpr::VK_Sparc_TLS_IE_LO10, DAG); + SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Base, TGA); + SDValue Offset = DAG.getNode(SPISD::TLS_LD, + DL, PtrVT, Ptr, +@@ -1930,14 +1940,15 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress + withTargetFlags(Op, ldTF, DAG)); + return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, + DAG.getRegister(SP::G7, PtrVT), Offset, +- withTargetFlags(Op, SPII::MO_TLS_IE_ADD, DAG)); ++ withTargetFlags(Op, ++ SparcMCExpr::VK_Sparc_TLS_IE_ADD, DAG)); + } + + assert(model == TLSModel::LocalExec); + SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT, +- withTargetFlags(Op, SPII::MO_TLS_LE_HIX22, DAG)); ++ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LE_HIX22, DAG)); + SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT, +- withTargetFlags(Op, SPII::MO_TLS_LE_LOX10, DAG)); ++ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LE_LOX10, DAG)); + SDValue Offset = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo); + + return DAG.getNode(ISD::ADD, DL, PtrVT, +Index: lib/Target/Sparc/SparcCodeEmitter.cpp +=================================================================== +--- lib/Target/Sparc/SparcCodeEmitter.cpp ++++ lib/Target/Sparc/SparcCodeEmitter.cpp +@@ -14,7 +14,7 @@ + + #define DEBUG_TYPE "jit" + #include "Sparc.h" +-#include "MCTargetDesc/SparcBaseInfo.h" ++#include "MCTargetDesc/SparcMCExpr.h" + #include "SparcRelocations.h" + #include "SparcTargetMachine.h" + #include "llvm/ADT/Statistic.h" +@@ -204,14 +204,14 @@ unsigned SparcCodeEmitter::getRelocation(const Mac + unsigned TF = MO.getTargetFlags(); + switch (TF) { + default: +- case SPII::MO_NO_FLAG: break; +- case SPII::MO_LO: return SP::reloc_sparc_lo; +- case SPII::MO_HI: return SP::reloc_sparc_hi; +- case SPII::MO_H44: return SP::reloc_sparc_h44; +- case SPII::MO_M44: return SP::reloc_sparc_m44; +- case SPII::MO_L44: return SP::reloc_sparc_l44; +- case SPII::MO_HH: return SP::reloc_sparc_hh; +- case SPII::MO_HM: return SP::reloc_sparc_hm; ++ case SparcMCExpr::VK_Sparc_None: break; ++ case SparcMCExpr::VK_Sparc_LO: return SP::reloc_sparc_lo; ++ case SparcMCExpr::VK_Sparc_HI: return SP::reloc_sparc_hi; ++ case SparcMCExpr::VK_Sparc_H44: return SP::reloc_sparc_h44; ++ case SparcMCExpr::VK_Sparc_M44: return SP::reloc_sparc_m44; ++ case SparcMCExpr::VK_Sparc_L44: return SP::reloc_sparc_l44; ++ case SparcMCExpr::VK_Sparc_HH: return SP::reloc_sparc_hh; ++ case SparcMCExpr::VK_Sparc_HM: return SP::reloc_sparc_hm; + } + + unsigned Opc = MI.getOpcode(); +Index: lib/Target/Sparc/SparcMCInstLower.cpp +=================================================================== +--- lib/Target/Sparc/SparcMCInstLower.cpp ++++ lib/Target/Sparc/SparcMCInstLower.cpp +@@ -13,7 +13,6 @@ + //===----------------------------------------------------------------------===// + + #include "Sparc.h" +-#include "MCTargetDesc/SparcBaseInfo.h" + #include "MCTargetDesc/SparcMCExpr.h" + #include "llvm/CodeGen/AsmPrinter.h" + #include "llvm/CodeGen/MachineFunction.h" +@@ -33,41 +32,10 @@ static MCOperand LowerSymbolOperand(const MachineI + const MachineOperand &MO, + AsmPrinter &AP) { + +- SparcMCExpr::VariantKind Kind; ++ SparcMCExpr::VariantKind Kind = ++ (SparcMCExpr::VariantKind)MO.getTargetFlags(); + const MCSymbol *Symbol = 0; + +- unsigned TF = MO.getTargetFlags(); +- +- switch(TF) { +- default: llvm_unreachable("Unknown target flags on operand"); +- case SPII::MO_NO_FLAG: Kind = SparcMCExpr::VK_Sparc_None; break; +- case SPII::MO_LO: Kind = SparcMCExpr::VK_Sparc_LO; break; +- case SPII::MO_HI: Kind = SparcMCExpr::VK_Sparc_HI; break; +- case SPII::MO_H44: Kind = SparcMCExpr::VK_Sparc_H44; break; +- case SPII::MO_M44: Kind = SparcMCExpr::VK_Sparc_M44; break; +- case SPII::MO_L44: Kind = SparcMCExpr::VK_Sparc_L44; break; +- case SPII::MO_HH: Kind = SparcMCExpr::VK_Sparc_HH; break; +- case SPII::MO_HM: Kind = SparcMCExpr::VK_Sparc_HM; break; +- case SPII::MO_TLS_GD_HI22: Kind = SparcMCExpr::VK_Sparc_TLS_GD_HI22; break; +- case SPII::MO_TLS_GD_LO10: Kind = SparcMCExpr::VK_Sparc_TLS_GD_LO10; break; +- case SPII::MO_TLS_GD_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_GD_ADD; break; +- case SPII::MO_TLS_GD_CALL: Kind = SparcMCExpr::VK_Sparc_TLS_GD_CALL; break; +- case SPII::MO_TLS_LDM_HI22: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_HI22; break; +- case SPII::MO_TLS_LDM_LO10: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_LO10; break; +- case SPII::MO_TLS_LDM_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_ADD; break; +- case SPII::MO_TLS_LDM_CALL: Kind = SparcMCExpr::VK_Sparc_TLS_LDM_CALL; break; +- case SPII::MO_TLS_LDO_HIX22:Kind = SparcMCExpr::VK_Sparc_TLS_LDO_HIX22; break; +- case SPII::MO_TLS_LDO_LOX10:Kind = SparcMCExpr::VK_Sparc_TLS_LDO_LOX10; break; +- case SPII::MO_TLS_LDO_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_LDO_ADD; break; +- case SPII::MO_TLS_IE_HI22: Kind = SparcMCExpr::VK_Sparc_TLS_IE_HI22; break; +- case SPII::MO_TLS_IE_LO10: Kind = SparcMCExpr::VK_Sparc_TLS_IE_LO10; break; +- case SPII::MO_TLS_IE_LD: Kind = SparcMCExpr::VK_Sparc_TLS_IE_LD; break; +- case SPII::MO_TLS_IE_LDX: Kind = SparcMCExpr::VK_Sparc_TLS_IE_LDX; break; +- case SPII::MO_TLS_IE_ADD: Kind = SparcMCExpr::VK_Sparc_TLS_IE_ADD; break; +- case SPII::MO_TLS_LE_HIX22: Kind = SparcMCExpr::VK_Sparc_TLS_LE_HIX22; break; +- case SPII::MO_TLS_LE_LOX10: Kind = SparcMCExpr::VK_Sparc_TLS_LE_LOX10; break; +- } +- + switch(MO.getType()) { + default: llvm_unreachable("Unknown type in LowerSymbolOperand"); + case MachineOperand::MO_MachineBasicBlock: +Index: lib/Target/Sparc/SparcAsmPrinter.cpp +=================================================================== +--- lib/Target/Sparc/SparcAsmPrinter.cpp ++++ lib/Target/Sparc/SparcAsmPrinter.cpp +@@ -18,7 +18,6 @@ + #include "SparcTargetMachine.h" + #include "SparcTargetStreamer.h" + #include "InstPrinter/SparcInstPrinter.h" +-#include "MCTargetDesc/SparcBaseInfo.h" + #include "MCTargetDesc/SparcMCExpr.h" + #include "llvm/ADT/SmallString.h" + #include "llvm/CodeGen/AsmPrinter.h" +@@ -287,83 +286,60 @@ void SparcAsmPrinter::EmitFunctionBodyStart() { + void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand (opNum); +- unsigned TF = MO.getTargetFlags(); ++ SparcMCExpr::VariantKind TF = (SparcMCExpr::VariantKind) MO.getTargetFlags(); ++ + #ifndef NDEBUG + // Verify the target flags. + if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) { + if (MI->getOpcode() == SP::CALL) +- assert(TF == SPII::MO_NO_FLAG && ++ assert(TF == SparcMCExpr::VK_Sparc_None && + "Cannot handle target flags on call address"); + else if (MI->getOpcode() == SP::SETHIi || MI->getOpcode() == SP::SETHIXi) +- assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH +- || TF == SPII::MO_TLS_GD_HI22 +- || TF == SPII::MO_TLS_LDM_HI22 +- || TF == SPII::MO_TLS_LDO_HIX22 +- || TF == SPII::MO_TLS_IE_HI22 +- || TF == SPII::MO_TLS_LE_HIX22) && ++ assert((TF == SparcMCExpr::VK_Sparc_HI ++ || TF == SparcMCExpr::VK_Sparc_H44 ++ || TF == SparcMCExpr::VK_Sparc_HH ++ || TF == SparcMCExpr::VK_Sparc_TLS_GD_HI22 ++ || TF == SparcMCExpr::VK_Sparc_TLS_LDM_HI22 ++ || TF == SparcMCExpr::VK_Sparc_TLS_LDO_HIX22 ++ || TF == SparcMCExpr::VK_Sparc_TLS_IE_HI22 ++ || TF == SparcMCExpr::VK_Sparc_TLS_LE_HIX22) && + "Invalid target flags for address operand on sethi"); + else if (MI->getOpcode() == SP::TLS_CALL) +- assert((TF == SPII::MO_NO_FLAG +- || TF == SPII::MO_TLS_GD_CALL +- || TF == SPII::MO_TLS_LDM_CALL) && ++ assert((TF == SparcMCExpr::VK_Sparc_None ++ || TF == SparcMCExpr::VK_Sparc_TLS_GD_CALL ++ || TF == SparcMCExpr::VK_Sparc_TLS_LDM_CALL) && + "Cannot handle target flags on tls call address"); + else if (MI->getOpcode() == SP::TLS_ADDrr) +- assert((TF == SPII::MO_TLS_GD_ADD || TF == SPII::MO_TLS_LDM_ADD +- || TF == SPII::MO_TLS_LDO_ADD || TF == SPII::MO_TLS_IE_ADD) && ++ assert((TF == SparcMCExpr::VK_Sparc_TLS_GD_ADD ++ || TF == SparcMCExpr::VK_Sparc_TLS_LDM_ADD ++ || TF == SparcMCExpr::VK_Sparc_TLS_LDO_ADD ++ || TF == SparcMCExpr::VK_Sparc_TLS_IE_ADD) && + "Cannot handle target flags on add for TLS"); + else if (MI->getOpcode() == SP::TLS_LDrr) +- assert(TF == SPII::MO_TLS_IE_LD && ++ assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LD && + "Cannot handle target flags on ld for TLS"); + else if (MI->getOpcode() == SP::TLS_LDXrr) +- assert(TF == SPII::MO_TLS_IE_LDX && ++ assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LDX && + "Cannot handle target flags on ldx for TLS"); + else if (MI->getOpcode() == SP::XORri || MI->getOpcode() == SP::XORXri) +- assert((TF == SPII::MO_TLS_LDO_LOX10 || TF == SPII::MO_TLS_LE_LOX10) && ++ assert((TF == SparcMCExpr::VK_Sparc_TLS_LDO_LOX10 ++ || TF == SparcMCExpr::VK_Sparc_TLS_LE_LOX10) && + "Cannot handle target flags on xor for TLS"); + else +- assert((TF == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44 +- || TF == SPII::MO_HM +- || TF == SPII::MO_TLS_GD_LO10 +- || TF == SPII::MO_TLS_LDM_LO10 +- || TF == SPII::MO_TLS_IE_LO10 ) && ++ assert((TF == SparcMCExpr::VK_Sparc_LO ++ || TF == SparcMCExpr::VK_Sparc_M44 ++ || TF == SparcMCExpr::VK_Sparc_L44 ++ || TF == SparcMCExpr::VK_Sparc_HM ++ || TF == SparcMCExpr::VK_Sparc_TLS_GD_LO10 ++ || TF == SparcMCExpr::VK_Sparc_TLS_LDM_LO10 ++ || TF == SparcMCExpr::VK_Sparc_TLS_IE_LO10 ) && + "Invalid target flags for small address operand"); + } + #endif + +- bool CloseParen = true; +- switch (TF) { +- default: +- llvm_unreachable("Unknown target flags on operand"); +- case SPII::MO_NO_FLAG: +- CloseParen = false; +- break; +- case SPII::MO_LO: O << "%lo("; break; +- case SPII::MO_HI: O << "%hi("; break; +- case SPII::MO_H44: O << "%h44("; break; +- case SPII::MO_M44: O << "%m44("; break; +- case SPII::MO_L44: O << "%l44("; break; +- case SPII::MO_HH: O << "%hh("; break; +- case SPII::MO_HM: O << "%hm("; break; +- case SPII::MO_TLS_GD_HI22: O << "%tgd_hi22("; break; +- case SPII::MO_TLS_GD_LO10: O << "%tgd_lo10("; break; +- case SPII::MO_TLS_GD_ADD: O << "%tgd_add("; break; +- case SPII::MO_TLS_GD_CALL: O << "%tgd_call("; break; +- case SPII::MO_TLS_LDM_HI22: O << "%tldm_hi22("; break; +- case SPII::MO_TLS_LDM_LO10: O << "%tldm_lo10("; break; +- case SPII::MO_TLS_LDM_ADD: O << "%tldm_add("; break; +- case SPII::MO_TLS_LDM_CALL: O << "%tldm_call("; break; +- case SPII::MO_TLS_LDO_HIX22: O << "%tldo_hix22("; break; +- case SPII::MO_TLS_LDO_LOX10: O << "%tldo_lox10("; break; +- case SPII::MO_TLS_LDO_ADD: O << "%tldo_add("; break; +- case SPII::MO_TLS_IE_HI22: O << "%tie_hi22("; break; +- case SPII::MO_TLS_IE_LO10: O << "%tie_lo10("; break; +- case SPII::MO_TLS_IE_LD: O << "%tie_ld("; break; +- case SPII::MO_TLS_IE_LDX: O << "%tie_ldx("; break; +- case SPII::MO_TLS_IE_ADD: O << "%tie_add("; break; +- case SPII::MO_TLS_LE_HIX22: O << "%tle_hix22("; break; +- case SPII::MO_TLS_LE_LOX10: O << "%tle_lox10("; break; +- } + ++ bool CloseParen = SparcMCExpr::printVariantKind(O, TF); ++ + switch (MO.getType()) { + case MachineOperand::MO_Register: + O << "%" << StringRef(getRegisterName(MO.getReg())).lower(); +Index: lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp +=================================================================== +--- lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp ++++ lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp +@@ -15,7 +15,6 @@ + #include "SparcInstPrinter.h" + + #include "Sparc.h" +-#include "MCTargetDesc/SparcBaseInfo.h" + #include "llvm/MC/MCExpr.h" + #include "llvm/MC/MCInst.h" + #include "llvm/MC/MCSymbol.h" +Index: lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h ++++ lib/Target/Sparc/MCTargetDesc/SparcBaseInfo.h +@@ -1,82 +0,0 @@ +-//===-- SparcBaseInfo.h - Top level definitions for Sparc ---- --*- C++ -*-===// +-// +-// The LLVM Compiler Infrastructure +-// +-// This file is distributed under the University of Illinois Open Source +-// License. See LICENSE.TXT for details. +-// +-//===----------------------------------------------------------------------===// +-// +-// This file contains small standalone helper functions and enum definitions +-// for the Sparc target useful for the compiler back-end and the MC libraries. +-// As such, it deliberately does not include references to LLVM core code gen +-// types, passes, etc.. +-// +-//===----------------------------------------------------------------------===// +- +-#ifndef SPARCBASEINFO_H +-#define SPARCBASEINFO_H +- +-namespace llvm { +- +-/// SPII - This namespace holds target specific flags for instruction info. +-namespace SPII { +- +-/// Target Operand Flags. Sparc specific TargetFlags for MachineOperands and +-/// SDNodes. +-enum TOF { +- MO_NO_FLAG, +- +- // Extract the low 10 bits of an address. +- // Assembler: %lo(addr) +- MO_LO, +- +- // Extract bits 31-10 of an address. Only for sethi. +- // Assembler: %hi(addr) or %lm(addr) +- MO_HI, +- +- // Extract bits 43-22 of an adress. Only for sethi. +- // Assembler: %h44(addr) +- MO_H44, +- +- // Extract bits 21-12 of an address. +- // Assembler: %m44(addr) +- MO_M44, +- +- // Extract bits 11-0 of an address. +- // Assembler: %l44(addr) +- MO_L44, +- +- // Extract bits 63-42 of an address. Only for sethi. +- // Assembler: %hh(addr) +- MO_HH, +- +- // Extract bits 41-32 of an address. +- // Assembler: %hm(addr) +- MO_HM, +- +- // TargetFlags for Thread Local Storage. +- MO_TLS_GD_HI22, +- MO_TLS_GD_LO10, +- MO_TLS_GD_ADD, +- MO_TLS_GD_CALL, +- MO_TLS_LDM_HI22, +- MO_TLS_LDM_LO10, +- MO_TLS_LDM_ADD, +- MO_TLS_LDM_CALL, +- MO_TLS_LDO_HIX22, +- MO_TLS_LDO_LOX10, +- MO_TLS_LDO_ADD, +- MO_TLS_IE_HI22, +- MO_TLS_IE_LO10, +- MO_TLS_IE_LD, +- MO_TLS_IE_LDX, +- MO_TLS_IE_ADD, +- MO_TLS_LE_HIX22, +- MO_TLS_LE_LOX10 +-}; +- +-} // end namespace SPII +-} // end namespace llvm +- +-#endif +Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +@@ -29,8 +29,21 @@ SparcMCExpr::Create(VariantKind Kind, const MCExpr + } + + ++ + void SparcMCExpr::PrintImpl(raw_ostream &OS) const + { ++ ++ bool closeParen = printVariantKind(OS, Kind); ++ ++ const MCExpr *Expr = getSubExpr(); ++ Expr->print(OS); ++ ++ if (closeParen) ++ OS << ')'; ++} ++ ++bool SparcMCExpr::printVariantKind(raw_ostream &OS, VariantKind Kind) ++{ + bool closeParen = true; + switch (Kind) { + case VK_Sparc_None: closeParen = false; break; +@@ -61,11 +74,7 @@ void SparcMCExpr::PrintImpl(raw_ostream &OS) const + case VK_Sparc_TLS_LE_HIX22: OS << "%tle_hix22("; break; + case VK_Sparc_TLS_LE_LOX10: OS << "%tle_lox10("; break; + } +- +- const MCExpr *Expr = getSubExpr(); +- Expr->print(OS); +- if (closeParen) +- OS << ')'; ++ return closeParen; + } + + SparcMCExpr::VariantKind SparcMCExpr::parseVariantKind(StringRef name) +Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h ++++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h +@@ -93,7 +93,7 @@ class SparcMCExpr : public MCTargetExpr { + static bool classof(const SparcMCExpr *) { return true; } + + static VariantKind parseVariantKind(StringRef name); +- ++ static bool printVariantKind(raw_ostream &OS, VariantKind Kind); + }; + + } // end namespace llvm. diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200961-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200961-sparc.diff new file mode 100644 index 0000000..a08d173 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200961-sparc.diff @@ -0,0 +1,443 @@ +Pull in r200961 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Emit correct relocations for PIC code when integrated assembler is used. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/CodeGen/SPARC/obj-relocs.ll +=================================================================== +--- test/CodeGen/SPARC/obj-relocs.ll ++++ test/CodeGen/SPARC/obj-relocs.ll +@@ -0,0 +1,33 @@ ++; RUN: llc < %s -march=sparcv9 -filetype=obj --relocation-model=static | llvm-readobj -r | FileCheck %s --check-prefix=CHECK-ABS ++; RUN: llc < %s -march=sparcv9 -filetype=obj --relocation-model=pic | llvm-readobj -r | FileCheck %s --check-prefix=CHECK-PIC ++ ++;CHECK-ABS: Relocations [ ++;CHECK-ABS: 0x{{[0-9,A-F]+}} R_SPARC_H44 AGlobalVar 0x0 ++;CHECK-ABS: 0x{{[0-9,A-F]+}} R_SPARC_M44 AGlobalVar 0x0 ++;CHECK-ABS: 0x{{[0-9,A-F]+}} R_SPARC_L44 AGlobalVar 0x0 ++;CHECK-ABS: 0x{{[0-9,A-F]+}} R_SPARC_WDISP30 bar 0x0 ++;CHECK-ABS:] ++ ++; CHECK-PIC: Relocations [ ++; CHECK-PIC: 0x{{[0-9,A-F]+}} R_SPARC_PC22 _GLOBAL_OFFSET_TABLE_ 0x4 ++; CHECK-PIC: 0x{{[0-9,A-F]+}} R_SPARC_PC10 _GLOBAL_OFFSET_TABLE_ 0x8 ++; CHECK-PIC: 0x{{[0-9,A-F]+}} R_SPARC_GOT22 AGlobalVar 0x0 ++; CHECK-PIC: 0x{{[0-9,A-F]+}} R_SPARC_GOT10 AGlobalVar 0x0 ++; CHECK-PIC: 0x{{[0-9,A-F]+}} R_SPARC_WPLT30 bar 0x0 ++; CHECK-PIC: ] ++ ++ ++@AGlobalVar = global i64 0, align 8 ++ ++; CHECK-ASM: sethi %h44(AGlobalVar), [[R:%[goli][0-7]]] ++; CHECK-ASM: add [[R]], %m44(AGlobalVar), [[R]] ++define i64 @foo(i64 %a) { ++entry: ++ %0 = load i64* @AGlobalVar, align 4 ++ %1 = add i64 %a, %0 ++ %2 = call i64 @bar(i64 %1) ++ ret i64 %2 ++} ++ ++ ++declare i64 @bar(i64) +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -895,10 +895,12 @@ SparcTargetLowering::LowerCall_32(TargetLowering:: + // If the callee is a GlobalAddress node (quite common, every direct call is) + // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. + // Likewise ExternalSymbol -> TargetExternalSymbol. ++ unsigned TF = ((getTargetMachine().getRelocationModel() == Reloc::PIC_) ++ ? SparcMCExpr::VK_Sparc_WPLT30 : 0); + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) +- Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32); ++ Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32, 0, TF); + else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) +- Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32); ++ Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32, TF); + + // Returns a chain & a flag for retval copy to use + SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); +@@ -1209,10 +1211,13 @@ SparcTargetLowering::LowerCall_64(TargetLowering:: + // Likewise ExternalSymbol -> TargetExternalSymbol. + SDValue Callee = CLI.Callee; + bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS); ++ unsigned TF = ((getTargetMachine().getRelocationModel() == Reloc::PIC_) ++ ? SparcMCExpr::VK_Sparc_WPLT30 : 0); + if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) +- Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy()); ++ Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy(), 0, ++ TF); + else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) +- Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy()); ++ Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy(), TF); + + // Build the operands for the call instruction itself. + SmallVector<SDValue, 8> Ops; +@@ -1796,8 +1801,8 @@ SDValue SparcTargetLowering::makeAddress(SDValue O + // Handle PIC mode first. + if (getTargetMachine().getRelocationModel() == Reloc::PIC_) { + // This is the pic32 code model, the GOT is known to be smaller than 4GB. +- SDValue HiLo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI, +- SparcMCExpr::VK_Sparc_LO, DAG); ++ SDValue HiLo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_GOT22, ++ SparcMCExpr::VK_Sparc_GOT10, DAG); + SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, VT); + SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, VT, GlobalBase, HiLo); + // GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this +Index: lib/Target/Sparc/SparcAsmPrinter.cpp +=================================================================== +--- lib/Target/Sparc/SparcAsmPrinter.cpp ++++ lib/Target/Sparc/SparcAsmPrinter.cpp +@@ -232,12 +232,12 @@ void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(co + MCOperand Callee = createPCXCallOP(EndLabel, OutContext); + EmitCall(OutStreamer, Callee); + OutStreamer.EmitLabel(SethiLabel); +- MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_HI, ++ MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22, + GOTLabel, StartLabel, SethiLabel, + OutContext); + EmitSETHI(OutStreamer, hiImm, MCRegOP); + OutStreamer.EmitLabel(EndLabel); +- MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_LO, ++ MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10, + GOTLabel, StartLabel, EndLabel, + OutContext); + EmitOR(OutStreamer, MCRegOP, loImm, MCRegOP); +Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +@@ -26,6 +26,7 @@ static unsigned adjustFixupValue(unsigned Kind, ui + case FK_Data_4: + case FK_Data_8: + return Value; ++ case Sparc::fixup_sparc_wplt30: + case Sparc::fixup_sparc_call30: + return (Value >> 2) & 0x3fffffff; + case Sparc::fixup_sparc_br22: +@@ -32,8 +33,12 @@ static unsigned adjustFixupValue(unsigned Kind, ui + return (Value >> 2) & 0x3fffff; + case Sparc::fixup_sparc_br19: + return (Value >> 2) & 0x7ffff; ++ case Sparc::fixup_sparc_pc22: ++ case Sparc::fixup_sparc_got22: + case Sparc::fixup_sparc_hi22: + return (Value >> 10) & 0x3fffff; ++ case Sparc::fixup_sparc_pc10: ++ case Sparc::fixup_sparc_got10: + case Sparc::fixup_sparc_lo10: + return Value & 0x3ff; + case Sparc::fixup_sparc_h44: +@@ -72,6 +77,11 @@ namespace { + { "fixup_sparc_l44", 20, 12, 0 }, + { "fixup_sparc_hh", 10, 22, 0 }, + { "fixup_sparc_hm", 22, 10, 0 }, ++ { "fixup_sparc_pc22", 10, 22, MCFixupKindInfo::FKF_IsPCRel }, ++ { "fixup_sparc_pc10", 22, 10, MCFixupKindInfo::FKF_IsPCRel }, ++ { "fixup_sparc_got22", 10, 22, 0 }, ++ { "fixup_sparc_got10", 22, 10, 0 }, ++ { "fixup_sparc_wplt30", 2, 30, MCFixupKindInfo::FKF_IsPCRel } + }; + + if (Kind < FirstTargetFixupKind) +@@ -82,6 +92,20 @@ namespace { + return Infos[Kind - FirstTargetFixupKind]; + } + ++ void processFixupValue(const MCAssembler &Asm, ++ const MCAsmLayout &Layout, ++ const MCFixup &Fixup, ++ const MCFragment *DF, ++ MCValue & Target, ++ uint64_t &Value, ++ bool &IsResolved) { ++ switch ((Sparc::Fixups)Fixup.getKind()) { ++ default: break; ++ case Sparc::fixup_sparc_wplt30: IsResolved = false; break; ++ } ++ } ++ ++ + bool mayNeedRelaxation(const MCInst &Inst) const { + // FIXME. + return false; +Index: lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h ++++ lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h +@@ -48,6 +48,21 @@ namespace llvm { + /// fixup_sparc_hm - 10-bit fixup corresponding to %hm(foo) + fixup_sparc_hm, + ++ /// fixup_sparc_pc22 - 22-bit fixup corresponding to %pc22(foo) ++ fixup_sparc_pc22, ++ ++ /// fixup_sparc_pc10 - 10-bit fixup corresponding to %pc10(foo) ++ fixup_sparc_pc10, ++ ++ /// fixup_sparc_got22 - 22-bit fixup corresponding to %got22(foo) ++ fixup_sparc_got22, ++ ++ /// fixup_sparc_got10 - 10-bit fixup corresponding to %got10(foo) ++ fixup_sparc_got10, ++ ++ /// fixup_sparc_wplt30 ++ fixup_sparc_wplt30, ++ + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind +Index: lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp +@@ -7,8 +7,9 @@ + // + //===----------------------------------------------------------------------===// + ++#include "MCTargetDesc/SparcFixupKinds.h" ++#include "MCTargetDesc/SparcMCExpr.h" + #include "MCTargetDesc/SparcMCTargetDesc.h" +-#include "MCTargetDesc/SparcFixupKinds.h" + #include "llvm/ADT/STLExtras.h" + #include "llvm/MC/MCELFObjectWriter.h" + #include "llvm/MC/MCExpr.h" +@@ -31,6 +32,11 @@ namespace { + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend) const; + ++ virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, ++ const MCValue &Target, ++ const MCFragment &F, ++ const MCFixup &Fixup, ++ bool IsPCRel) const; + }; + } + +@@ -40,6 +46,12 @@ unsigned SparcELFObjectWriter::GetRelocType(const + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) const { ++ ++ if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Fixup.getValue())) { ++ if (SExpr->getKind() == SparcMCExpr::VK_Sparc_R_DISP32) ++ return ELF::R_SPARC_DISP32; ++ } ++ + if (IsPCRel) { + switch((unsigned)Fixup.getKind()) { + default: +@@ -51,6 +63,9 @@ unsigned SparcELFObjectWriter::GetRelocType(const + case Sparc::fixup_sparc_call30: return ELF::R_SPARC_WDISP30; + case Sparc::fixup_sparc_br22: return ELF::R_SPARC_WDISP22; + case Sparc::fixup_sparc_br19: return ELF::R_SPARC_WDISP19; ++ case Sparc::fixup_sparc_pc22: return ELF::R_SPARC_PC22; ++ case Sparc::fixup_sparc_pc10: return ELF::R_SPARC_PC10; ++ case Sparc::fixup_sparc_wplt30: return ELF::R_SPARC_WPLT30; + } + } + +@@ -74,10 +89,30 @@ unsigned SparcELFObjectWriter::GetRelocType(const + case Sparc::fixup_sparc_l44: return ELF::R_SPARC_L44; + case Sparc::fixup_sparc_hh: return ELF::R_SPARC_HH22; + case Sparc::fixup_sparc_hm: return ELF::R_SPARC_HM10; ++ case Sparc::fixup_sparc_got22: return ELF::R_SPARC_GOT22; ++ case Sparc::fixup_sparc_got10: return ELF::R_SPARC_GOT10; + } ++ + return ELF::R_SPARC_NONE; + } + ++const MCSymbol *SparcELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm, ++ const MCValue &Target, ++ const MCFragment &F, ++ const MCFixup &Fixup, ++ bool IsPCRel) const { ++ ++ if (!Target.getSymA()) ++ return NULL; ++ switch((unsigned)Fixup.getKind()) { ++ default: break; ++ case Sparc::fixup_sparc_got22: ++ case Sparc::fixup_sparc_got10: ++ return &Target.getSymA()->getSymbol().AliasedSymbol(); ++ } ++ return NULL; ++} ++ + MCObjectWriter *llvm::createSparcELFObjectWriter(raw_ostream &OS, + bool Is64Bit, + uint8_t OSABI) { +Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +@@ -17,6 +17,7 @@ + #include "llvm/MC/MCContext.h" + #include "llvm/MC/MCAssembler.h" + #include "llvm/MC/MCELF.h" ++#include "llvm/MC/MCSymbol.h" + #include "llvm/Object/ELF.h" + + +@@ -54,6 +55,13 @@ bool SparcMCExpr::printVariantKind(raw_ostream &OS + case VK_Sparc_L44: OS << "%l44("; break; + case VK_Sparc_HH: OS << "%hh("; break; + case VK_Sparc_HM: OS << "%hm("; break; ++ // FIXME: use %pc22/%pc10, if system assembler supports them. ++ case VK_Sparc_PC22: OS << "%hi("; break; ++ case VK_Sparc_PC10: OS << "%lo("; break; ++ // FIXME: use %got22/%got10, if system assembler supports them. ++ case VK_Sparc_GOT22: OS << "%hi("; break; ++ case VK_Sparc_GOT10: OS << "%lo("; break; ++ case VK_Sparc_WPLT30: closeParen = false; break; + case VK_Sparc_R_DISP32: OS << "%r_disp32("; break; + case VK_Sparc_TLS_GD_HI22: OS << "%tgd_hi22("; break; + case VK_Sparc_TLS_GD_LO10: OS << "%tgd_lo10("; break; +@@ -87,6 +95,10 @@ SparcMCExpr::VariantKind SparcMCExpr::parseVariant + .Case("l44", VK_Sparc_L44) + .Case("hh", VK_Sparc_HH) + .Case("hm", VK_Sparc_HM) ++ .Case("pc22", VK_Sparc_PC22) ++ .Case("pc10", VK_Sparc_PC10) ++ .Case("got22", VK_Sparc_GOT22) ++ .Case("got10", VK_Sparc_GOT10) + .Case("r_disp32", VK_Sparc_R_DISP32) + .Case("tgd_hi22", VK_Sparc_TLS_GD_HI22) + .Case("tgd_lo10", VK_Sparc_TLS_GD_LO10) +@@ -109,9 +121,26 @@ SparcMCExpr::VariantKind SparcMCExpr::parseVariant + .Default(VK_Sparc_None); + } + ++Sparc::Fixups SparcMCExpr::getFixupKind(SparcMCExpr::VariantKind Kind) { ++ switch (Kind) { ++ default: assert(0 && "Unhandled SparcMCExpr::VariantKind"); ++ case VK_Sparc_LO: return Sparc::fixup_sparc_lo10; ++ case VK_Sparc_HI: return Sparc::fixup_sparc_hi22; ++ case VK_Sparc_H44: return Sparc::fixup_sparc_h44; ++ case VK_Sparc_M44: return Sparc::fixup_sparc_m44; ++ case VK_Sparc_L44: return Sparc::fixup_sparc_l44; ++ case VK_Sparc_HH: return Sparc::fixup_sparc_hh; ++ case VK_Sparc_HM: return Sparc::fixup_sparc_hm; ++ case VK_Sparc_PC22: return Sparc::fixup_sparc_pc22; ++ case VK_Sparc_PC10: return Sparc::fixup_sparc_pc10; ++ case VK_Sparc_GOT22: return Sparc::fixup_sparc_got22; ++ case VK_Sparc_GOT10: return Sparc::fixup_sparc_got10; ++ } ++} ++ + bool + SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Res, +- const MCAsmLayout *Layout) const { ++ const MCAsmLayout *Layout) const { + if (!Layout) + return false; + return getSubExpr()->EvaluateAsRelocatable(Res, *Layout); +Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h ++++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h +@@ -15,6 +15,7 @@ + #ifndef LLVM_SPARCMCEXPR_H + #define LLVM_SPARCMCEXPR_H + ++#include "SparcFixupKinds.h" + #include "llvm/MC/MCExpr.h" + + namespace llvm { +@@ -31,6 +32,11 @@ class SparcMCExpr : public MCTargetExpr { + VK_Sparc_L44, + VK_Sparc_HH, + VK_Sparc_HM, ++ VK_Sparc_PC22, ++ VK_Sparc_PC10, ++ VK_Sparc_GOT22, ++ VK_Sparc_GOT10, ++ VK_Sparc_WPLT30, + VK_Sparc_R_DISP32, + VK_Sparc_TLS_GD_HI22, + VK_Sparc_TLS_GD_LO10, +@@ -75,6 +81,9 @@ class SparcMCExpr : public MCTargetExpr { + /// getSubExpr - Get the child of this expression. + const MCExpr *getSubExpr() const { return Expr; } + ++ /// getFixupKind - Get the fixup kind of this expression. ++ Sparc::Fixups getFixupKind() const { return getFixupKind(Kind); } ++ + /// @} + void PrintImpl(raw_ostream &OS) const; + bool EvaluateAsRelocatableImpl(MCValue &Res, +@@ -94,6 +103,7 @@ class SparcMCExpr : public MCTargetExpr { + + static VariantKind parseVariantKind(StringRef name); + static bool printVariantKind(raw_ostream &OS, VariantKind Kind); ++ static Sparc::Fixups getFixupKind(VariantKind Kind); + }; + + } // end namespace llvm. +Index: lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp +@@ -94,37 +94,8 @@ getMachineOpValue(const MCInst &MI, const MCOperan + assert(MO.isExpr()); + const MCExpr *Expr = MO.getExpr(); + if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Expr)) { +- switch(SExpr->getKind()) { +- default: assert(0 && "Unhandled sparc expression!"); break; +- case SparcMCExpr::VK_Sparc_LO: +- Fixups.push_back(MCFixup::Create(0, Expr, +- (MCFixupKind)Sparc::fixup_sparc_lo10)); +- break; +- case SparcMCExpr::VK_Sparc_HI: +- Fixups.push_back(MCFixup::Create(0, Expr, +- (MCFixupKind)Sparc::fixup_sparc_hi22)); +- break; +- case SparcMCExpr::VK_Sparc_H44: +- Fixups.push_back(MCFixup::Create(0, Expr, +- (MCFixupKind)Sparc::fixup_sparc_h44)); +- break; +- case SparcMCExpr::VK_Sparc_M44: +- Fixups.push_back(MCFixup::Create(0, Expr, +- (MCFixupKind)Sparc::fixup_sparc_m44)); +- break; +- case SparcMCExpr::VK_Sparc_L44: +- Fixups.push_back(MCFixup::Create(0, Expr, +- (MCFixupKind)Sparc::fixup_sparc_l44)); +- break; +- case SparcMCExpr::VK_Sparc_HH: +- Fixups.push_back(MCFixup::Create(0, Expr, +- (MCFixupKind)Sparc::fixup_sparc_hh)); +- break; +- case SparcMCExpr::VK_Sparc_HM: +- Fixups.push_back(MCFixup::Create(0, Expr, +- (MCFixupKind)Sparc::fixup_sparc_hm)); +- break; +- } ++ MCFixupKind Kind = (MCFixupKind)SExpr->getFixupKind(); ++ Fixups.push_back(MCFixup::Create(0, Expr, Kind)); + return 0; + } + +@@ -143,8 +114,15 @@ getCallTargetOpValue(const MCInst &MI, unsigned Op + if (MO.isReg() || MO.isImm()) + return getMachineOpValue(MI, MO, Fixups); + +- Fixups.push_back(MCFixup::Create(0, MO.getExpr(), +- (MCFixupKind)Sparc::fixup_sparc_call30)); ++ MCFixupKind fixupKind = (MCFixupKind)Sparc::fixup_sparc_call30; ++ ++ if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(MO.getExpr())) { ++ if (SExpr->getKind() == SparcMCExpr::VK_Sparc_WPLT30) ++ fixupKind = (MCFixupKind)Sparc::fixup_sparc_wplt30; ++ } ++ ++ Fixups.push_back(MCFixup::Create(0, MO.getExpr(), fixupKind)); ++ + return 0; + } + diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200962-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200962-sparc.diff new file mode 100644 index 0000000..2e668a3 --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200962-sparc.diff @@ -0,0 +1,378 @@ +Pull in r200962 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Emit relocations for Thread Local Storage (TLS) when integrated assembler is used. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +@@ -26,31 +26,65 @@ static unsigned adjustFixupValue(unsigned Kind, ui + case FK_Data_4: + case FK_Data_8: + return Value; ++ + case Sparc::fixup_sparc_wplt30: + case Sparc::fixup_sparc_call30: + return (Value >> 2) & 0x3fffffff; ++ + case Sparc::fixup_sparc_br22: + return (Value >> 2) & 0x3fffff; ++ + case Sparc::fixup_sparc_br19: + return (Value >> 2) & 0x7ffff; ++ + case Sparc::fixup_sparc_pc22: + case Sparc::fixup_sparc_got22: ++ case Sparc::fixup_sparc_tls_gd_hi22: ++ case Sparc::fixup_sparc_tls_ldm_hi22: ++ case Sparc::fixup_sparc_tls_ie_hi22: + case Sparc::fixup_sparc_hi22: + return (Value >> 10) & 0x3fffff; ++ + case Sparc::fixup_sparc_pc10: + case Sparc::fixup_sparc_got10: ++ case Sparc::fixup_sparc_tls_gd_lo10: ++ case Sparc::fixup_sparc_tls_ldm_lo10: ++ case Sparc::fixup_sparc_tls_ie_lo10: + case Sparc::fixup_sparc_lo10: + return Value & 0x3ff; ++ ++ case Sparc::fixup_sparc_tls_ldo_hix22: ++ case Sparc::fixup_sparc_tls_le_hix22: ++ return (~Value >> 10) & 0x3fffff; ++ ++ case Sparc::fixup_sparc_tls_ldo_lox10: ++ case Sparc::fixup_sparc_tls_le_lox10: ++ return (~(~Value & 0x3ff)) & 0x1fff; ++ + case Sparc::fixup_sparc_h44: + return (Value >> 22) & 0x3fffff; ++ + case Sparc::fixup_sparc_m44: + return (Value >> 12) & 0x3ff; ++ + case Sparc::fixup_sparc_l44: + return Value & 0xfff; ++ + case Sparc::fixup_sparc_hh: + return (Value >> 42) & 0x3fffff; ++ + case Sparc::fixup_sparc_hm: + return (Value >> 32) & 0x3ff; ++ ++ case Sparc::fixup_sparc_tls_gd_add: ++ case Sparc::fixup_sparc_tls_gd_call: ++ case Sparc::fixup_sparc_tls_ldm_add: ++ case Sparc::fixup_sparc_tls_ldm_call: ++ case Sparc::fixup_sparc_tls_ldo_add: ++ case Sparc::fixup_sparc_tls_ie_ld: ++ case Sparc::fixup_sparc_tls_ie_ldx: ++ case Sparc::fixup_sparc_tls_ie_add: ++ return 0; + } + } + +@@ -81,7 +115,25 @@ namespace { + { "fixup_sparc_pc10", 22, 10, MCFixupKindInfo::FKF_IsPCRel }, + { "fixup_sparc_got22", 10, 22, 0 }, + { "fixup_sparc_got10", 22, 10, 0 }, +- { "fixup_sparc_wplt30", 2, 30, MCFixupKindInfo::FKF_IsPCRel } ++ { "fixup_sparc_wplt30", 2, 30, MCFixupKindInfo::FKF_IsPCRel }, ++ { "fixup_sparc_tls_gd_hi22", 10, 22, 0 }, ++ { "fixup_sparc_tls_gd_lo10", 22, 10, 0 }, ++ { "fixup_sparc_tls_gd_add", 0, 0, 0 }, ++ { "fixup_sparc_tls_gd_call", 0, 0, 0 }, ++ { "fixup_sparc_tls_ldm_hi22", 10, 22, 0 }, ++ { "fixup_sparc_tls_ldm_lo10", 22, 10, 0 }, ++ { "fixup_sparc_tls_ldm_add", 0, 0, 0 }, ++ { "fixup_sparc_tls_ldm_call", 0, 0, 0 }, ++ { "fixup_sparc_tls_ldo_hix22", 10, 22, 0 }, ++ { "fixup_sparc_tls_ldo_lox10", 22, 10, 0 }, ++ { "fixup_sparc_tls_ldo_add", 0, 0, 0 }, ++ { "fixup_sparc_tls_ie_hi22", 10, 22, 0 }, ++ { "fixup_sparc_tls_ie_lo10", 22, 10, 0 }, ++ { "fixup_sparc_tls_ie_ld", 0, 0, 0 }, ++ { "fixup_sparc_tls_ie_ldx", 0, 0, 0 }, ++ { "fixup_sparc_tls_ie_add", 0, 0, 0 }, ++ { "fixup_sparc_tls_le_hix22", 0, 0, 0 }, ++ { "fixup_sparc_tls_le_lox10", 0, 0, 0 } + }; + + if (Kind < FirstTargetFixupKind) +@@ -101,11 +153,28 @@ namespace { + bool &IsResolved) { + switch ((Sparc::Fixups)Fixup.getKind()) { + default: break; +- case Sparc::fixup_sparc_wplt30: IsResolved = false; break; ++ case Sparc::fixup_sparc_wplt30: ++ case Sparc::fixup_sparc_tls_gd_hi22: ++ case Sparc::fixup_sparc_tls_gd_lo10: ++ case Sparc::fixup_sparc_tls_gd_add: ++ case Sparc::fixup_sparc_tls_gd_call: ++ case Sparc::fixup_sparc_tls_ldm_hi22: ++ case Sparc::fixup_sparc_tls_ldm_lo10: ++ case Sparc::fixup_sparc_tls_ldm_add: ++ case Sparc::fixup_sparc_tls_ldm_call: ++ case Sparc::fixup_sparc_tls_ldo_hix22: ++ case Sparc::fixup_sparc_tls_ldo_lox10: ++ case Sparc::fixup_sparc_tls_ldo_add: ++ case Sparc::fixup_sparc_tls_ie_hi22: ++ case Sparc::fixup_sparc_tls_ie_lo10: ++ case Sparc::fixup_sparc_tls_ie_ld: ++ case Sparc::fixup_sparc_tls_ie_ldx: ++ case Sparc::fixup_sparc_tls_ie_add: ++ case Sparc::fixup_sparc_tls_le_hix22: ++ case Sparc::fixup_sparc_tls_le_lox10: IsResolved = false; break; + } + } + +- + bool mayNeedRelaxation(const MCInst &Inst) const { + // FIXME. + return false; +Index: lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h ++++ lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h +@@ -63,6 +63,26 @@ namespace llvm { + /// fixup_sparc_wplt30 + fixup_sparc_wplt30, + ++ /// fixups for Thread Local Storage ++ fixup_sparc_tls_gd_hi22, ++ fixup_sparc_tls_gd_lo10, ++ fixup_sparc_tls_gd_add, ++ fixup_sparc_tls_gd_call, ++ fixup_sparc_tls_ldm_hi22, ++ fixup_sparc_tls_ldm_lo10, ++ fixup_sparc_tls_ldm_add, ++ fixup_sparc_tls_ldm_call, ++ fixup_sparc_tls_ldo_hix22, ++ fixup_sparc_tls_ldo_lox10, ++ fixup_sparc_tls_ldo_add, ++ fixup_sparc_tls_ie_hi22, ++ fixup_sparc_tls_ie_lo10, ++ fixup_sparc_tls_ie_ld, ++ fixup_sparc_tls_ie_ldx, ++ fixup_sparc_tls_ie_add, ++ fixup_sparc_tls_le_hix22, ++ fixup_sparc_tls_le_lox10, ++ + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind +Index: lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp +@@ -91,6 +91,24 @@ unsigned SparcELFObjectWriter::GetRelocType(const + case Sparc::fixup_sparc_hm: return ELF::R_SPARC_HM10; + case Sparc::fixup_sparc_got22: return ELF::R_SPARC_GOT22; + case Sparc::fixup_sparc_got10: return ELF::R_SPARC_GOT10; ++ case Sparc::fixup_sparc_tls_gd_hi22: return ELF::R_SPARC_TLS_GD_HI22; ++ case Sparc::fixup_sparc_tls_gd_lo10: return ELF::R_SPARC_TLS_GD_LO10; ++ case Sparc::fixup_sparc_tls_gd_add: return ELF::R_SPARC_TLS_GD_ADD; ++ case Sparc::fixup_sparc_tls_gd_call: return ELF::R_SPARC_TLS_GD_CALL; ++ case Sparc::fixup_sparc_tls_ldm_hi22: return ELF::R_SPARC_TLS_LDM_HI22; ++ case Sparc::fixup_sparc_tls_ldm_lo10: return ELF::R_SPARC_TLS_LDM_LO10; ++ case Sparc::fixup_sparc_tls_ldm_add: return ELF::R_SPARC_TLS_LDM_ADD; ++ case Sparc::fixup_sparc_tls_ldm_call: return ELF::R_SPARC_TLS_LDM_CALL; ++ case Sparc::fixup_sparc_tls_ldo_hix22: return ELF::R_SPARC_TLS_LDO_HIX22; ++ case Sparc::fixup_sparc_tls_ldo_lox10: return ELF::R_SPARC_TLS_LDO_LOX10; ++ case Sparc::fixup_sparc_tls_ldo_add: return ELF::R_SPARC_TLS_LDO_ADD; ++ case Sparc::fixup_sparc_tls_ie_hi22: return ELF::R_SPARC_TLS_IE_HI22; ++ case Sparc::fixup_sparc_tls_ie_lo10: return ELF::R_SPARC_TLS_IE_LO10; ++ case Sparc::fixup_sparc_tls_ie_ld: return ELF::R_SPARC_TLS_IE_LD; ++ case Sparc::fixup_sparc_tls_ie_ldx: return ELF::R_SPARC_TLS_IE_LDX; ++ case Sparc::fixup_sparc_tls_ie_add: return ELF::R_SPARC_TLS_IE_ADD; ++ case Sparc::fixup_sparc_tls_le_hix22: return ELF::R_SPARC_TLS_LE_HIX22; ++ case Sparc::fixup_sparc_tls_le_lox10: return ELF::R_SPARC_TLS_LE_LOX10; + } + + return ELF::R_SPARC_NONE; +Index: lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp +@@ -135,6 +135,25 @@ Sparc::Fixups SparcMCExpr::getFixupKind(SparcMCExp + case VK_Sparc_PC10: return Sparc::fixup_sparc_pc10; + case VK_Sparc_GOT22: return Sparc::fixup_sparc_got22; + case VK_Sparc_GOT10: return Sparc::fixup_sparc_got10; ++ case VK_Sparc_WPLT30: return Sparc::fixup_sparc_wplt30; ++ case VK_Sparc_TLS_GD_HI22: return Sparc::fixup_sparc_tls_gd_hi22; ++ case VK_Sparc_TLS_GD_LO10: return Sparc::fixup_sparc_tls_gd_lo10; ++ case VK_Sparc_TLS_GD_ADD: return Sparc::fixup_sparc_tls_gd_add; ++ case VK_Sparc_TLS_GD_CALL: return Sparc::fixup_sparc_tls_gd_call; ++ case VK_Sparc_TLS_LDM_HI22: return Sparc::fixup_sparc_tls_ldm_hi22; ++ case VK_Sparc_TLS_LDM_LO10: return Sparc::fixup_sparc_tls_ldm_lo10; ++ case VK_Sparc_TLS_LDM_ADD: return Sparc::fixup_sparc_tls_ldm_add; ++ case VK_Sparc_TLS_LDM_CALL: return Sparc::fixup_sparc_tls_ldm_call; ++ case VK_Sparc_TLS_LDO_HIX22: return Sparc::fixup_sparc_tls_ldo_hix22; ++ case VK_Sparc_TLS_LDO_LOX10: return Sparc::fixup_sparc_tls_ldo_lox10; ++ case VK_Sparc_TLS_LDO_ADD: return Sparc::fixup_sparc_tls_ldo_add; ++ case VK_Sparc_TLS_IE_HI22: return Sparc::fixup_sparc_tls_ie_hi22; ++ case VK_Sparc_TLS_IE_LO10: return Sparc::fixup_sparc_tls_ie_lo10; ++ case VK_Sparc_TLS_IE_LD: return Sparc::fixup_sparc_tls_ie_ld; ++ case VK_Sparc_TLS_IE_LDX: return Sparc::fixup_sparc_tls_ie_ldx; ++ case VK_Sparc_TLS_IE_ADD: return Sparc::fixup_sparc_tls_ie_add; ++ case VK_Sparc_TLS_LE_HIX22: return Sparc::fixup_sparc_tls_le_hix22; ++ case VK_Sparc_TLS_LE_LOX10: return Sparc::fixup_sparc_tls_le_lox10; + } + } + +@@ -147,7 +166,33 @@ SparcMCExpr::EvaluateAsRelocatableImpl(MCValue &Re + } + + static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) { +- assert(0 && "Implement fixELFSymbolsInTLSFixupsImpl!"); ++ switch (Expr->getKind()) { ++ case MCExpr::Target: ++ llvm_unreachable("Can't handle nested target expr!"); ++ break; ++ ++ case MCExpr::Constant: ++ break; ++ ++ case MCExpr::Binary: { ++ const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr); ++ fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm); ++ fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm); ++ break; ++ } ++ ++ case MCExpr::SymbolRef: { ++ const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr); ++ MCSymbolData &SD = Asm.getOrCreateSymbolData(SymRef.getSymbol()); ++ MCELF::SetType(SD, ELF::STT_TLS); ++ break; ++ } ++ ++ case MCExpr::Unary: ++ fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm); ++ break; ++ } ++ + } + + void SparcMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const { +Index: lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp +=================================================================== +--- lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp ++++ lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp +@@ -20,6 +20,7 @@ + #include "llvm/MC/MCExpr.h" + #include "llvm/MC/MCInst.h" + #include "llvm/MC/MCRegisterInfo.h" ++#include "llvm/MC/MCSymbol.h" + #include "llvm/ADT/Statistic.h" + #include "llvm/Support/raw_ostream.h" + +@@ -76,6 +77,21 @@ EncodeInstruction(const MCInst &MI, raw_ostream &O + OS << (char)(Bits >> 24); + Bits <<= 8; + } ++ unsigned tlsOpNo = 0; ++ switch (MI.getOpcode()) { ++ default: break; ++ case SP::TLS_CALL: tlsOpNo = 1; break; ++ case SP::TLS_ADDrr: ++ case SP::TLS_ADDXrr: ++ case SP::TLS_LDrr: ++ case SP::TLS_LDXrr: tlsOpNo = 3; break; ++ } ++ if (tlsOpNo != 0) { ++ const MCOperand &MO = MI.getOperand(tlsOpNo); ++ uint64_t op = getMachineOpValue(MI, MO, Fixups); ++ assert(op == 0 && "Unexpected operand value!"); ++ (void)op; // suppress warning. ++ } + + ++MCNumEmitted; // Keep track of the # of mi's emitted. + } +@@ -114,6 +130,21 @@ getCallTargetOpValue(const MCInst &MI, unsigned Op + if (MO.isReg() || MO.isImm()) + return getMachineOpValue(MI, MO, Fixups); + ++ if (MI.getOpcode() == SP::TLS_CALL) { ++ // No fixups for __tls_get_addr. Will emit for fixups for tls_symbol in ++ // EncodeInstruction. ++#ifndef NDEBUG ++ // Verify that the callee is actually __tls_get_addr. ++ const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(MO.getExpr()); ++ assert(SExpr && SExpr->getSubExpr()->getKind() == MCExpr::SymbolRef && ++ "Unexpected expression in TLS_CALL"); ++ const MCSymbolRefExpr *SymExpr = cast<MCSymbolRefExpr>(SExpr->getSubExpr()); ++ assert(SymExpr->getSymbol().getName() == "__tls_get_addr" && ++ "Unexpected function for TLS_CALL"); ++#endif ++ return 0; ++ } ++ + MCFixupKind fixupKind = (MCFixupKind)Sparc::fixup_sparc_call30; + + if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(MO.getExpr())) { +Index: test/CodeGen/SPARC/tls.ll +=================================================================== +--- test/CodeGen/SPARC/tls.ll ++++ test/CodeGen/SPARC/tls.ll +@@ -3,6 +3,10 @@ + ; RUN: llc <%s -march=sparc -relocation-model=pic | FileCheck %s --check-prefix=pic + ; RUN: llc <%s -march=sparcv9 -relocation-model=pic | FileCheck %s --check-prefix=pic + ++; RUN: llc <%s -march=sparc -relocation-model=static -filetype=obj | llvm-readobj -r | FileCheck %s --check-prefix=v8abs-obj ++; RUN: llc <%s -march=sparcv9 -relocation-model=static -filetype=obj | llvm-readobj -r | FileCheck %s --check-prefix=v9abs-obj ++; RUN: llc <%s -march=sparc -relocation-model=pic -filetype=obj | llvm-readobj -r | FileCheck %s --check-prefix=pic-obj ++; RUN: llc <%s -march=sparcv9 -relocation-model=pic -filetype=obj | llvm-readobj -r | FileCheck %s --check-prefix=pic-obj + + @local_symbol = internal thread_local global i32 0 + @extern_symbol = external thread_local global i32 +@@ -69,3 +73,47 @@ entry: + store i32 %1, i32* @extern_symbol, align 4 + ret i32 %1 + } ++ ++ ++; v8abs-obj: Relocations [ ++; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LE_HIX22 local_symbol 0x0 ++; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LE_LOX10 local_symbol 0x0 ++; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_HI22 _GLOBAL_OFFSET_TABLE_ 0x0 ++; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_LO10 _GLOBAL_OFFSET_TABLE_ 0x0 ++; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_HI22 extern_symbol 0x0 ++; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_LO10 extern_symbol 0x0 ++; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_LD extern_symbol 0x0 ++; v8abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_ADD extern_symbol 0x0 ++; v8abs-obj: ] ++ ++; v9abs-obj: Relocations [ ++; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LE_HIX22 local_symbol 0x0 ++; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LE_LOX10 local_symbol 0x0 ++; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_H44 _GLOBAL_OFFSET_TABLE_ 0x0 ++; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_M44 _GLOBAL_OFFSET_TABLE_ 0x0 ++; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_L44 _GLOBAL_OFFSET_TABLE_ 0x0 ++; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_HI22 extern_symbol 0x0 ++; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_LO10 extern_symbol 0x0 ++; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_LDX extern_symbol 0x0 ++; v9abs-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_IE_ADD extern_symbol 0x0 ++; v9abs-obj: ] ++ ++; pic-obj: Relocations [ ++; pic-obj: Section (2) .rela.text { ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_PC22 _GLOBAL_OFFSET_TABLE_ 0x4 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_PC10 _GLOBAL_OFFSET_TABLE_ 0x8 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDO_HIX22 local_symbol 0x0 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDO_LOX10 local_symbol 0x0 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDM_HI22 local_symbol 0x0 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDM_LO10 local_symbol 0x0 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDM_ADD local_symbol 0x0 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDM_CALL local_symbol 0x0 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_LDO_ADD local_symbol 0x0 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_PC22 _GLOBAL_OFFSET_TABLE_ 0x4 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_PC10 _GLOBAL_OFFSET_TABLE_ 0x8 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_GD_HI22 extern_symbol 0x0 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_GD_LO10 extern_symbol 0x0 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_GD_ADD extern_symbol 0x0 ++; pic-obj: 0x{{[0-9,A-F]+}} R_SPARC_TLS_GD_CALL extern_symbol 0x0 ++; pic-obj: ] ++ diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200963-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200963-sparc.diff new file mode 100644 index 0000000..f8a817e --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200963-sparc.diff @@ -0,0 +1,131 @@ +Pull in r200963 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Emit correct encoding for atomic instructions. Also, add support for parsing CAS instructions to test the CAS encoding. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: test/MC/Sparc/sparc-atomic-instructions.s +=================================================================== +--- test/MC/Sparc/sparc-atomic-instructions.s ++++ test/MC/Sparc/sparc-atomic-instructions.s +@@ -0,0 +1,19 @@ ++! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s ++ ++ ! CHECK: membar 15 ! encoding: [0x81,0x43,0xe0,0x0f] ++ membar 15 ++ ++ ! CHECK: stbar ! encoding: [0x81,0x43,0xc0,0x00] ++ stbar ++ ++ ! CHECK: swap [%i0+%l6], %o2 ! encoding: [0xd4,0x7e,0x00,0x16] ++ swap [%i0+%l6], %o2 ++ ++ ! CHECK: swap [%i0+32], %o2 ! encoding: [0xd4,0x7e,0x20,0x20] ++ swap [%i0+32], %o2 ++ ++ ! CHECK: cas [%i0], %l6, %o2 ! encoding: [0xd5,0xe6,0x10,0x16] ++ cas [%i0], %l6, %o2 ++ ++ ! CHECK: casx [%i0], %l6, %o2 ! encoding: [0xd5,0xf6,0x10,0x16] ++ casx [%i0], %l6, %o2 +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -935,19 +935,19 @@ let Predicates = [HasV9], hasSideEffects = 1, rd = + def MEMBARi : F3_2<2, 0b101000, (outs), (ins i32imm:$simm13), + "membar $simm13", []>; + +-let Constraints = "$val = $rd" in { ++let Constraints = "$val = $dst" in { + def SWAPrr : F3_1<3, 0b001111, +- (outs IntRegs:$rd), (ins IntRegs:$val, MEMrr:$addr), +- "swap [$addr], $rd", +- [(set i32:$rd, (atomic_swap_32 ADDRrr:$addr, i32:$val))]>; ++ (outs IntRegs:$dst), (ins MEMrr:$addr, IntRegs:$val), ++ "swap [$addr], $dst", ++ [(set i32:$dst, (atomic_swap_32 ADDRrr:$addr, i32:$val))]>; + def SWAPri : F3_2<3, 0b001111, +- (outs IntRegs:$rd), (ins IntRegs:$val, MEMri:$addr), +- "swap [$addr], $rd", +- [(set i32:$rd, (atomic_swap_32 ADDRri:$addr, i32:$val))]>; ++ (outs IntRegs:$dst), (ins MEMri:$addr, IntRegs:$val), ++ "swap [$addr], $dst", ++ [(set i32:$dst, (atomic_swap_32 ADDRri:$addr, i32:$val))]>; + } + + let Predicates = [HasV9], Constraints = "$swap = $rd" in +- def CASrr: F3_1<3, 0b111100, ++ def CASrr: F3_1_asi<3, 0b111100, 0b10000000, + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, + IntRegs:$swap), + "cas [$rs1], $rs2, $rd", +Index: lib/Target/Sparc/SparcInstrFormats.td +=================================================================== +--- lib/Target/Sparc/SparcInstrFormats.td ++++ lib/Target/Sparc/SparcInstrFormats.td +@@ -100,9 +100,8 @@ class F3<dag outs, dag ins, string asmstr, list<da + + // Specific F3 classes: SparcV8 manual, page 44 + // +-class F3_1<bits<2> opVal, bits<6> op3val, dag outs, dag ins, ++class F3_1_asi<bits<2> opVal, bits<6> op3val, bits<8> asi, dag outs, dag ins, + string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { +- bits<8> asi = 0; // asi not currently used + bits<5> rs2; + + let op = opVal; +@@ -113,6 +112,10 @@ class F3<dag outs, dag ins, string asmstr, list<da + let Inst{4-0} = rs2; + } + ++class F3_1<bits<2> opVal, bits<6> op3val, dag outs, dag ins, string asmstr, ++ list<dag> pattern> : F3_1_asi<opVal, op3val, 0, outs, ins, ++ asmstr, pattern>; ++ + class F3_2<bits<2> opVal, bits<6> op3val, dag outs, dag ins, + string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { + bits<13> simm13; +Index: lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +=================================================================== +--- lib/Target/Sparc/AsmParser/SparcAsmParser.cpp ++++ lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +@@ -546,7 +546,24 @@ parseOperand(SmallVectorImpl<MCParsedAsmOperand*> + Parser.getTok().getLoc())); + Parser.Lex(); // Eat the [ + +- ResTy = parseMEMOperand(Operands); ++ if (Mnemonic == "cas" || Mnemonic == "casx") { ++ SMLoc S = Parser.getTok().getLoc(); ++ if (getLexer().getKind() != AsmToken::Percent) ++ return MatchOperand_NoMatch; ++ Parser.Lex(); // eat % ++ ++ unsigned RegNo, RegKind; ++ if (!matchRegisterName(Parser.getTok(), RegNo, RegKind)) ++ return MatchOperand_NoMatch; ++ ++ Parser.Lex(); // Eat the identifier token. ++ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer()-1); ++ Operands.push_back(SparcOperand::CreateReg(RegNo, RegKind, S, E)); ++ ResTy = MatchOperand_Success; ++ } else { ++ ResTy = parseMEMOperand(Operands); ++ } ++ + if (ResTy != MatchOperand_Success) + return ResTy; + +Index: lib/Target/Sparc/SparcInstr64Bit.td +=================================================================== +--- lib/Target/Sparc/SparcInstr64Bit.td ++++ lib/Target/Sparc/SparcInstr64Bit.td +@@ -415,7 +415,7 @@ def SETHIXi : F2_1<0b100, + + // ATOMICS. + let Predicates = [Is64Bit], Constraints = "$swap = $rd" in { +- def CASXrr: F3_1<3, 0b111110, ++ def CASXrr: F3_1_asi<3, 0b111110, 0b10000000, + (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2, + I64Regs:$swap), + "casx [$rs1], $rs2, $rd", diff --git a/contrib/llvm/patches/patch-r262261-llvm-r200965-sparc.diff b/contrib/llvm/patches/patch-r262261-llvm-r200965-sparc.diff new file mode 100644 index 0000000..2b0d41e --- /dev/null +++ b/contrib/llvm/patches/patch-r262261-llvm-r200965-sparc.diff @@ -0,0 +1,33 @@ +Pull in r200965 from upstream llvm trunk (by Venkatraman Govindaraju): + + [Sparc] Add support for parsing synthetic instruction 'mov'. + +Introduced here: http://svn.freebsd.org/changeset/base/262261 + +Index: lib/Target/Sparc/SparcInstrAliases.td +=================================================================== +--- lib/Target/Sparc/SparcInstrAliases.td ++++ lib/Target/Sparc/SparcInstrAliases.td +@@ -134,3 +134,9 @@ def : InstAlias<"retl", (RETL 8)>; + + // ret -> RET 8 + def : InstAlias<"ret", (RET 8)>; ++ ++// mov reg, rd -> or %g0, reg, rd ++def : InstAlias<"mov $rs2, $rd", (ORrr IntRegs:$rd, G0, IntRegs:$rs2)>; ++ ++// mov simm13, rd -> or %g0, simm13, rd ++def : InstAlias<"mov $simm13, $rd", (ORri IntRegs:$rd, G0, i32imm:$simm13)>; +Index: test/MC/Sparc/sparc-alu-instructions.s +=================================================================== +--- test/MC/Sparc/sparc-alu-instructions.s ++++ test/MC/Sparc/sparc-alu-instructions.s +@@ -70,3 +70,8 @@ + ! CHECK: subxcc %g1, %g2, %g3 ! encoding: [0x86,0xe0,0x40,0x02] + subxcc %g1, %g2, %g3 + ++ ! CHECK: or %g0, %g1, %g3 ! encoding: [0x86,0x10,0x00,0x01] ++ mov %g1, %g3 ++ ++ ! CHECK: or %g0, 255, %g3 ! encoding: [0x86,0x10,0x20,0xff] ++ mov 0xff, %g3 diff --git a/contrib/llvm/patches/patch-r262262-clang-r198311-sparc.diff b/contrib/llvm/patches/patch-r262262-clang-r198311-sparc.diff new file mode 100644 index 0000000..751b976 --- /dev/null +++ b/contrib/llvm/patches/patch-r262262-clang-r198311-sparc.diff @@ -0,0 +1,31 @@ +Pull in r198311 from upstream clang trunk (by Roman Divacky): + + In the FreeBSD assembler driver, inform the sparc assembler that we're producing + PIC code. + +Introduced here: http://svn.freebsd.org/changeset/base/262262 + +Index: tools/clang/lib/Driver/Tools.cpp +=================================================================== +--- tools/clang/lib/Driver/Tools.cpp ++++ tools/clang/lib/Driver/Tools.cpp +@@ -5785,6 +5785,19 @@ void freebsd::Assemble::ConstructJob(Compilation & + default: + CmdArgs.push_back("-matpcs"); + } ++ } else if (getToolChain().getArch() == llvm::Triple::sparc || ++ getToolChain().getArch() == llvm::Triple::sparcv9) { ++ Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, ++ options::OPT_fpic, options::OPT_fno_pic, ++ options::OPT_fPIE, options::OPT_fno_PIE, ++ options::OPT_fpie, options::OPT_fno_pie); ++ if (LastPICArg && ++ (LastPICArg->getOption().matches(options::OPT_fPIC) || ++ LastPICArg->getOption().matches(options::OPT_fpic) || ++ LastPICArg->getOption().matches(options::OPT_fPIE) || ++ LastPICArg->getOption().matches(options::OPT_fpie))) { ++ CmdArgs.push_back("-KPIC"); ++ } + } + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, diff --git a/contrib/llvm/patches/patch-r262262-clang-r198312-sparc.diff b/contrib/llvm/patches/patch-r262262-clang-r198312-sparc.diff new file mode 100644 index 0000000..8903d38 --- /dev/null +++ b/contrib/llvm/patches/patch-r262262-clang-r198312-sparc.diff @@ -0,0 +1,19 @@ +Pull in r198312 from upstream clang trunk (by Roman Divacky): + + Remove a tab that snuck in. + +Introduced here: http://svn.freebsd.org/changeset/base/262262 + +Index: tools/clang/lib/Driver/Tools.cpp +=================================================================== +--- tools/clang/lib/Driver/Tools.cpp ++++ tools/clang/lib/Driver/Tools.cpp +@@ -5786,7 +5786,7 @@ void freebsd::Assemble::ConstructJob(Compilation & + CmdArgs.push_back("-matpcs"); + } + } else if (getToolChain().getArch() == llvm::Triple::sparc || +- getToolChain().getArch() == llvm::Triple::sparcv9) { ++ getToolChain().getArch() == llvm::Triple::sparcv9) { + Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, + options::OPT_fpic, options::OPT_fno_pic, + options::OPT_fPIE, options::OPT_fno_PIE, diff --git a/contrib/llvm/patches/patch-r262262-clang-r198911-sparc.diff b/contrib/llvm/patches/patch-r262262-clang-r198911-sparc.diff new file mode 100644 index 0000000..d50b53f --- /dev/null +++ b/contrib/llvm/patches/patch-r262262-clang-r198911-sparc.diff @@ -0,0 +1,46 @@ +Pull in r198911 from upstream clang trunk (by Jakob Stoklund Olesen): + + Pass -32/-64 to the assembler when building for sparc/sparc64. + +Introduced here: http://svn.freebsd.org/changeset/base/262262 + +Index: tools/clang/test/Driver/linux-as.c +=================================================================== +--- tools/clang/test/Driver/linux-as.c ++++ tools/clang/test/Driver/linux-as.c +@@ -60,6 +60,20 @@ + // RUN: | FileCheck -check-prefix=CHECK-PPC-NO-MCPU %s + // CHECK-PPC-NO-MCPU-NOT: as{{.*}} "-mcpu=invalid-cpu" + // ++// RUN: %clang -target sparc64-linux -mcpu=invalid-cpu -### \ ++// RUN: -no-integrated-as -c %s 2>&1 \ ++// RUN: | FileCheck -check-prefix=CHECK-SPARCV9 %s ++// CHECK-SPARCV9: as ++// CHECK-SPARCV9: -64 ++// CHECK-SPARCV9: -o ++// ++// RUN: %clang -target sparc-linux -mcpu=invalid-cpu -### \ ++// RUN: -no-integrated-as -c %s 2>&1 \ ++// RUN: | FileCheck -check-prefix=CHECK-SPARCV8 %s ++// CHECK-SPARCV8: as ++// CHECK-SPARCV8: -32 ++// CHECK-SPARCV8: -o ++// + // RUN: %clang -target s390x-linux -### -no-integrated-as -c %s 2>&1 \ + // RUN: | FileCheck -check-prefix=CHECK-Z-DEFAULT-ARCH %s + // CHECK-Z-DEFAULT-ARCH: as{{.*}} "-march=z10" +Index: tools/clang/lib/Driver/Tools.cpp +=================================================================== +--- tools/clang/lib/Driver/Tools.cpp ++++ tools/clang/lib/Driver/Tools.cpp +@@ -6226,6 +6226,10 @@ void gnutools::Assemble::ConstructJob(Compilation + CmdArgs.push_back("-a64"); + CmdArgs.push_back("-mppc64le"); + CmdArgs.push_back("-many"); ++ } else if (getToolChain().getArch() == llvm::Triple::sparc) { ++ CmdArgs.push_back("-32"); ++ } else if (getToolChain().getArch() == llvm::Triple::sparcv9) { ++ CmdArgs.push_back("-64"); + } else if (getToolChain().getArch() == llvm::Triple::arm) { + StringRef MArch = getToolChain().getArchName(); + if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") diff --git a/contrib/llvm/patches/patch-r262262-clang-r198912-sparc.diff b/contrib/llvm/patches/patch-r262262-clang-r198912-sparc.diff new file mode 100644 index 0000000..9e3ce43 --- /dev/null +++ b/contrib/llvm/patches/patch-r262262-clang-r198912-sparc.diff @@ -0,0 +1,44 @@ +Pull in r198912 from upstream clang trunk (by Jakob Stoklund Olesen): + + Give the linker the right ELF type for SPARC targets. + +Introduced here: http://svn.freebsd.org/changeset/base/262262 + +Index: tools/clang/lib/Driver/Tools.cpp +=================================================================== +--- tools/clang/lib/Driver/Tools.cpp ++++ tools/clang/lib/Driver/Tools.cpp +@@ -6461,6 +6461,10 @@ void gnutools::Link::ConstructJob(Compilation &C, + CmdArgs.push_back("elf32ppclinux"); + else if (ToolChain.getArch() == llvm::Triple::ppc64) + CmdArgs.push_back("elf64ppc"); ++ else if (ToolChain.getArch() == llvm::Triple::sparc) ++ CmdArgs.push_back("elf32_sparc"); ++ else if (ToolChain.getArch() == llvm::Triple::sparcv9) ++ CmdArgs.push_back("elf64_sparc"); + else if (ToolChain.getArch() == llvm::Triple::mips) + CmdArgs.push_back("elf32btsmip"); + else if (ToolChain.getArch() == llvm::Triple::mipsel) +Index: tools/clang/test/Driver/linux-ld.c +=================================================================== +--- tools/clang/test/Driver/linux-ld.c ++++ tools/clang/test/Driver/linux-ld.c +@@ -384,6 +384,18 @@ + // CHECK-MIPS64EL-N32: "-dynamic-linker" "{{.*}}/lib32/ld.so.1" + // CHECK-MIPS64EL-N32-NOT: "--hash-style={{gnu|both}}" + // ++// RUN: %clang %s -### -o %t.o 2>&1 \ ++// RUN: --target=sparc-linux-gnu \ ++// RUN: | FileCheck --check-prefix=CHECK-SPARCV8 %s ++// CHECK-SPARCV8: "{{.*}}ld{{(.exe)?}}" ++// CHECK-SPARCV8: "-m" "elf32_sparc" ++// ++// RUN: %clang %s -### -o %t.o 2>&1 \ ++// RUN: --target=sparcv9-linux-gnu \ ++// RUN: | FileCheck --check-prefix=CHECK-SPARCV9 %s ++// CHECK-SPARCV9: "{{.*}}ld{{(.exe)?}}" ++// CHECK-SPARCV9: "-m" "elf64_sparc" ++// + // Thoroughly exercise the Debian multiarch environment. + // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ + // RUN: --target=i686-linux-gnu \ diff --git a/contrib/llvm/patches/patch-r262262-clang-r198918-sparc.diff b/contrib/llvm/patches/patch-r262262-clang-r198918-sparc.diff new file mode 100644 index 0000000..a3c6026 --- /dev/null +++ b/contrib/llvm/patches/patch-r262262-clang-r198918-sparc.diff @@ -0,0 +1,59 @@ +Pull in r198918 from upstream clang trunk (by Jakob Stoklund Olesen): + + Locate GCC installations on SPARC systems. + +Introduced here: http://svn.freebsd.org/changeset/base/262262 + +Index: tools/clang/lib/Driver/ToolChains.cpp +=================================================================== +--- tools/clang/lib/Driver/ToolChains.cpp ++++ tools/clang/lib/Driver/ToolChains.cpp +@@ -1164,6 +1164,13 @@ void Generic_GCC::GCCInstallationDetector::print(r + "powerpc64le-suse-linux", + "ppc64le-redhat-linux" }; + ++ static const char *const SPARCv8LibDirs[] = { "/lib32", "/lib" }; ++ static const char *const SPARCv8Triples[] = { "sparc-linux-gnu", ++ "sparcv8-linux-gnu" }; ++ static const char *const SPARCv9LibDirs[] = { "/lib64", "/lib" }; ++ static const char *const SPARCv9Triples[] = { "sparc64-linux-gnu", ++ "sparcv9-linux-gnu" }; ++ + static const char *const SystemZLibDirs[] = { "/lib64", "/lib" }; + static const char *const SystemZTriples[] = { + "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", +@@ -1283,6 +1290,26 @@ void Generic_GCC::GCCInstallationDetector::print(r + TripleAliases.append(PPC64LETriples, + PPC64LETriples + llvm::array_lengthof(PPC64LETriples)); + break; ++ case llvm::Triple::sparc: ++ LibDirs.append(SPARCv8LibDirs, ++ SPARCv8LibDirs + llvm::array_lengthof(SPARCv8LibDirs)); ++ TripleAliases.append(SPARCv8Triples, ++ SPARCv8Triples + llvm::array_lengthof(SPARCv8Triples)); ++ BiarchLibDirs.append(SPARCv9LibDirs, ++ SPARCv9LibDirs + llvm::array_lengthof(SPARCv9LibDirs)); ++ BiarchTripleAliases.append( ++ SPARCv9Triples, SPARCv9Triples + llvm::array_lengthof(SPARCv9Triples)); ++ break; ++ case llvm::Triple::sparcv9: ++ LibDirs.append(SPARCv9LibDirs, ++ SPARCv9LibDirs + llvm::array_lengthof(SPARCv9LibDirs)); ++ TripleAliases.append(SPARCv9Triples, ++ SPARCv9Triples + llvm::array_lengthof(SPARCv9Triples)); ++ BiarchLibDirs.append(SPARCv8LibDirs, ++ SPARCv8LibDirs + llvm::array_lengthof(SPARCv8LibDirs)); ++ BiarchTripleAliases.append( ++ SPARCv8Triples, SPARCv8Triples + llvm::array_lengthof(SPARCv8Triples)); ++ break; + case llvm::Triple::systemz: + LibDirs.append(SystemZLibDirs, + SystemZLibDirs + llvm::array_lengthof(SystemZLibDirs)); +@@ -1379,6 +1406,7 @@ static bool findTargetBiarchSuffix(std::string &Su + Suffix = "/n32"; + else if (TargetArch == llvm::Triple::x86_64 || + TargetArch == llvm::Triple::ppc64 || ++ TargetArch == llvm::Triple::sparcv9 || + TargetArch == llvm::Triple::systemz || + TargetArch == llvm::Triple::mips64 || + TargetArch == llvm::Triple::mips64el) diff --git a/contrib/llvm/patches/patch-r262262-clang-r198923-sparc.diff b/contrib/llvm/patches/patch-r262262-clang-r198923-sparc.diff new file mode 100644 index 0000000..912aa62 --- /dev/null +++ b/contrib/llvm/patches/patch-r262262-clang-r198923-sparc.diff @@ -0,0 +1,49 @@ +Pull in r198923 from upstream clang trunk (by Jakob Stoklund Olesen): + + Use the right dynamic linker for SPARC Linux executables. + +Introduced here: http://svn.freebsd.org/changeset/base/262262 + +Index: tools/clang/lib/Driver/Tools.cpp +=================================================================== +--- tools/clang/lib/Driver/Tools.cpp ++++ tools/clang/lib/Driver/Tools.cpp +@@ -6374,7 +6374,8 @@ static StringRef getLinuxDynamicLinker(const ArgLi + const toolchains::Linux &ToolChain) { + if (ToolChain.getTriple().getEnvironment() == llvm::Triple::Android) + return "/system/bin/linker"; +- else if (ToolChain.getArch() == llvm::Triple::x86) ++ else if (ToolChain.getArch() == llvm::Triple::x86 || ++ ToolChain.getArch() == llvm::Triple::sparc) + return "/lib/ld-linux.so.2"; + else if (ToolChain.getArch() == llvm::Triple::aarch64) + return "/lib/ld-linux-aarch64.so.1"; +@@ -6399,6 +6400,8 @@ static StringRef getLinuxDynamicLinker(const ArgLi + ToolChain.getArch() == llvm::Triple::ppc64le || + ToolChain.getArch() == llvm::Triple::systemz) + return "/lib64/ld64.so.1"; ++ else if (ToolChain.getArch() == llvm::Triple::sparcv9) ++ return "/lib64/ld-linux.so.2"; + else + return "/lib64/ld-linux-x86-64.so.2"; + } +Index: tools/clang/test/Driver/linux-ld.c +=================================================================== +--- tools/clang/test/Driver/linux-ld.c ++++ tools/clang/test/Driver/linux-ld.c +@@ -389,6 +389,7 @@ + // RUN: | FileCheck --check-prefix=CHECK-SPARCV8 %s + // CHECK-SPARCV8: "{{.*}}ld{{(.exe)?}}" + // CHECK-SPARCV8: "-m" "elf32_sparc" ++// CHECK-SPARCV8: "-dynamic-linker" "/lib/ld-linux.so.2" + // + // RUN: %clang %s -### -o %t.o 2>&1 \ + // RUN: --target=sparcv9-linux-gnu \ +@@ -395,6 +396,7 @@ + // RUN: | FileCheck --check-prefix=CHECK-SPARCV9 %s + // CHECK-SPARCV9: "{{.*}}ld{{(.exe)?}}" + // CHECK-SPARCV9: "-m" "elf64_sparc" ++// CHECK-SPARCV9: "-dynamic-linker" "/lib64/ld-linux.so.2" + // + // Thoroughly exercise the Debian multiarch environment. + // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ diff --git a/contrib/llvm/patches/patch-r262262-clang-r199012-sparc.diff b/contrib/llvm/patches/patch-r262262-clang-r199012-sparc.diff new file mode 100644 index 0000000..7bc4a78 --- /dev/null +++ b/contrib/llvm/patches/patch-r262262-clang-r199012-sparc.diff @@ -0,0 +1,41 @@ +Pull in r199012 from upstream clang trunk (by Jakob Stoklund Olesen): + + Select the UltraSPARC instruction set when invoking the assembler. + +Introduced here: http://svn.freebsd.org/changeset/base/262262 + +Index: tools/clang/lib/Driver/Tools.cpp +=================================================================== +--- tools/clang/lib/Driver/Tools.cpp ++++ tools/clang/lib/Driver/Tools.cpp +@@ -6228,8 +6228,10 @@ void gnutools::Assemble::ConstructJob(Compilation + CmdArgs.push_back("-many"); + } else if (getToolChain().getArch() == llvm::Triple::sparc) { + CmdArgs.push_back("-32"); ++ CmdArgs.push_back("-Av8plusa"); + } else if (getToolChain().getArch() == llvm::Triple::sparcv9) { + CmdArgs.push_back("-64"); ++ CmdArgs.push_back("-Av9a"); + } else if (getToolChain().getArch() == llvm::Triple::arm) { + StringRef MArch = getToolChain().getArchName(); + if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") +Index: tools/clang/test/Driver/linux-as.c +=================================================================== +--- tools/clang/test/Driver/linux-as.c ++++ tools/clang/test/Driver/linux-as.c +@@ -65,6 +65,7 @@ + // RUN: | FileCheck -check-prefix=CHECK-SPARCV9 %s + // CHECK-SPARCV9: as + // CHECK-SPARCV9: -64 ++// CHECK-SPARCV9: -Av9a + // CHECK-SPARCV9: -o + // + // RUN: %clang -target sparc-linux -mcpu=invalid-cpu -### \ +@@ -72,6 +73,7 @@ + // RUN: | FileCheck -check-prefix=CHECK-SPARCV8 %s + // CHECK-SPARCV8: as + // CHECK-SPARCV8: -32 ++// CHECK-SPARCV8: -Av8plusa + // CHECK-SPARCV8: -o + // + // RUN: %clang -target s390x-linux -### -no-integrated-as -c %s 2>&1 \ diff --git a/contrib/llvm/patches/patch-r262262-clang-r199034-sparc.diff b/contrib/llvm/patches/patch-r262262-clang-r199034-sparc.diff new file mode 100644 index 0000000..8043e1f --- /dev/null +++ b/contrib/llvm/patches/patch-r262262-clang-r199034-sparc.diff @@ -0,0 +1,81 @@ +Pull in r199034 from upstream clang trunk (by Jakob Stoklund Olesen): + + MIPS and SPARC assemblers both take the -KPIC flag. + +Introduced here: http://svn.freebsd.org/changeset/base/262262 + +Index: tools/clang/lib/Driver/Tools.cpp +=================================================================== +--- tools/clang/lib/Driver/Tools.cpp ++++ tools/clang/lib/Driver/Tools.cpp +@@ -6207,6 +6207,7 @@ void gnutools::Assemble::ConstructJob(Compilation + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; ++ bool NeedsKPIC = false; + + // Add --32/--64 to make sure we get the format we want. + // This is incomplete +@@ -6229,9 +6230,11 @@ void gnutools::Assemble::ConstructJob(Compilation + } else if (getToolChain().getArch() == llvm::Triple::sparc) { + CmdArgs.push_back("-32"); + CmdArgs.push_back("-Av8plusa"); ++ NeedsKPIC = true; + } else if (getToolChain().getArch() == llvm::Triple::sparcv9) { + CmdArgs.push_back("-64"); + CmdArgs.push_back("-Av9a"); ++ NeedsKPIC = true; + } else if (getToolChain().getArch() == llvm::Triple::arm) { + StringRef MArch = getToolChain().getArchName(); + if (MArch == "armv7" || MArch == "armv7a" || MArch == "armv7-a") +@@ -6291,6 +6294,15 @@ void gnutools::Assemble::ConstructJob(Compilation + CmdArgs.push_back(Args.MakeArgString("-mmsa")); + } + ++ NeedsKPIC = true; ++ } else if (getToolChain().getArch() == llvm::Triple::systemz) { ++ // Always pass an -march option, since our default of z10 is later ++ // than the GNU assembler's default. ++ StringRef CPUName = getSystemZTargetCPU(Args); ++ CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); ++ } ++ ++ if (NeedsKPIC) { + Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, + options::OPT_fpic, options::OPT_fno_pic, + options::OPT_fPIE, options::OPT_fno_PIE, +@@ -6302,11 +6314,6 @@ void gnutools::Assemble::ConstructJob(Compilation + LastPICArg->getOption().matches(options::OPT_fpie))) { + CmdArgs.push_back("-KPIC"); + } +- } else if (getToolChain().getArch() == llvm::Triple::systemz) { +- // Always pass an -march option, since our default of z10 is later +- // than the GNU assembler's default. +- StringRef CPUName = getSystemZTargetCPU(Args); +- CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); + } + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, +Index: tools/clang/test/Driver/linux-as.c +=================================================================== +--- tools/clang/test/Driver/linux-as.c ++++ tools/clang/test/Driver/linux-as.c +@@ -66,8 +66,18 @@ + // CHECK-SPARCV9: as + // CHECK-SPARCV9: -64 + // CHECK-SPARCV9: -Av9a ++// CHECK-SPARCV9-NOT: -KPIC + // CHECK-SPARCV9: -o + // ++// RUN: %clang -target sparc64-linux -mcpu=invalid-cpu -### \ ++// RUN: -no-integrated-as -fpic -c %s 2>&1 \ ++// RUN: | FileCheck -check-prefix=CHECK-SPARCV9PIC %s ++// CHECK-SPARCV9PIC: as ++// CHECK-SPARCV9PIC: -64 ++// CHECK-SPARCV9PIC: -Av9a ++// CHECK-SPARCV9PIC: -KPIC ++// CHECK-SPARCV9PIC: -o ++// + // RUN: %clang -target sparc-linux -mcpu=invalid-cpu -### \ + // RUN: -no-integrated-as -c %s 2>&1 \ + // RUN: | FileCheck -check-prefix=CHECK-SPARCV8 %s diff --git a/contrib/llvm/patches/patch-r262262-clang-r199037-sparc.diff b/contrib/llvm/patches/patch-r262262-clang-r199037-sparc.diff new file mode 100644 index 0000000..beed0ed --- /dev/null +++ b/contrib/llvm/patches/patch-r262262-clang-r199037-sparc.diff @@ -0,0 +1,53 @@ +Pull in r199037 from upstream clang trunk (by Jakob Stokund Olesen): + + SPARC passes non-trivial C++ objects indirectly like everybody else. + +Introduced here: http://svn.freebsd.org/changeset/base/262262 + +Index: tools/clang/lib/CodeGen/TargetInfo.cpp +=================================================================== +--- tools/clang/lib/CodeGen/TargetInfo.cpp ++++ tools/clang/lib/CodeGen/TargetInfo.cpp +@@ -5349,6 +5349,11 @@ SparcV9ABIInfo::classifyType(QualType Ty, unsigned + if (!isAggregateTypeForABI(Ty)) + return ABIArgInfo::getDirect(); + ++ // If a C++ object has either a non-trivial copy constructor or a non-trivial ++ // destructor, it is passed with an explicit indirect pointer / sret pointer. ++ if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) ++ return ABIArgInfo::getIndirect(0, RAA == CGCXXABI::RAA_DirectInMemory); ++ + // This is a small aggregate type that should be passed in registers. + // Build a coercion type from the LLVM struct type. + llvm::StructType *StrTy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty)); +Index: tools/clang/test/CodeGenCXX/sparcv9-abi.cpp +=================================================================== +--- tools/clang/test/CodeGenCXX/sparcv9-abi.cpp ++++ tools/clang/test/CodeGenCXX/sparcv9-abi.cpp +@@ -0,0 +1,26 @@ ++// RUN: %clang_cc1 -triple sparcv9-unknown-unknown -emit-llvm %s -o - | FileCheck %s ++ ++struct pod { ++ int a, b; ++}; ++ ++void f0(); ++void f1(struct pod); ++ ++struct notpod { ++ int a, b; ++ ~notpod() { f0(); } ++}; ++ ++void f2(struct notpod); ++ ++// CHECK-LABEL: caller ++// CHECK: call void @_Z2f13pod(i64 ++// CHECK: call void @_Z2f26notpod(%struct.notpod* ++void caller() ++{ ++ pod p1; ++ notpod p2; ++ f1(p1); ++ f2(p2); ++} diff --git a/contrib/llvm/patches/patch-r262262-clang-r199188-sparc.diff b/contrib/llvm/patches/patch-r262262-clang-r199188-sparc.diff new file mode 100644 index 0000000..77e5eaf --- /dev/null +++ b/contrib/llvm/patches/patch-r262262-clang-r199188-sparc.diff @@ -0,0 +1,35 @@ +Pull in r199188 from upstream clang trunk (by Jakob Stoklund Olesen): + + Puny 24-byte structs are returned by value on SPARC. + + Pad these structs up so they are sret-returned even on that + architecture. + +Introduced here: http://svn.freebsd.org/changeset/base/262262 + +Index: tools/clang/test/CodeGen/sret.c +=================================================================== +--- tools/clang/test/CodeGen/sret.c ++++ tools/clang/test/CodeGen/sret.c +@@ -4,6 +4,8 @@ struct abc { + long a; + long b; + long c; ++ long d; ++ long e; + }; + + struct abc foo1(void); +Index: tools/clang/test/CodeGen/sret2.c +=================================================================== +--- tools/clang/test/CodeGen/sret2.c ++++ tools/clang/test/CodeGen/sret2.c +@@ -4,6 +4,8 @@ struct abc { + long a; + long b; + long c; ++ long d; ++ long e; + }; + + struct abc foo2(){} diff --git a/contrib/llvm/patches/patch-r262262-clang-r199399-sparc.diff b/contrib/llvm/patches/patch-r262262-clang-r199399-sparc.diff new file mode 100644 index 0000000..106ab89 --- /dev/null +++ b/contrib/llvm/patches/patch-r262262-clang-r199399-sparc.diff @@ -0,0 +1,37 @@ +Pull in r199399 from upstream clang trunk (by Jakob Stoklund Olesen): + + SPARCv9 implements long double as an IEEE quad. + +Introduced here: http://svn.freebsd.org/changeset/base/262262 + +Index: tools/clang/test/CodeGen/sparcv9-abi.c +=================================================================== +--- tools/clang/test/CodeGen/sparcv9-abi.c ++++ tools/clang/test/CodeGen/sparcv9-abi.c +@@ -18,6 +18,9 @@ long long f_int_3(long long x) { return x; } + // CHECK-LABEL: define signext i8 @f_int_4(i8 signext %x) + char f_int_4(char x) { return x; } + ++// CHECK-LABEL: define fp128 @f_ld(fp128 %x) ++long double f_ld(long double x) { return x; } ++ + // Small structs are passed in registers. + struct small { + int *a, *b; +Index: tools/clang/lib/Basic/Targets.cpp +=================================================================== +--- tools/clang/lib/Basic/Targets.cpp ++++ tools/clang/lib/Basic/Targets.cpp +@@ -4529,6 +4529,12 @@ class SparcV9TargetInfo : public SparcTargetInfo { + UIntMaxType = UnsignedLong; + } + Int64Type = IntMaxType; ++ ++ // The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit ++ // aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned. ++ LongDoubleWidth = 128; ++ LongDoubleAlign = 128; ++ LongDoubleFormat = &llvm::APFloat::IEEEquad; + } + + virtual void getTargetDefines(const LangOptions &Opts, diff --git a/contrib/llvm/patches/patch-r262262-clang-r200452-sparc.diff b/contrib/llvm/patches/patch-r262262-clang-r200452-sparc.diff new file mode 100644 index 0000000..e14306d --- /dev/null +++ b/contrib/llvm/patches/patch-r262262-clang-r200452-sparc.diff @@ -0,0 +1,20 @@ +Pull in r200452 from upstream clang trunk (by Jakob Stoklund Olesen): + + SPARCv9 supports atomic operations up to 64 bits. + + Patch by Roman Divacky! + +Introduced here: http://svn.freebsd.org/changeset/base/262262 + +Index: tools/clang/lib/Basic/Targets.cpp +=================================================================== +--- tools/clang/lib/Basic/Targets.cpp ++++ tools/clang/lib/Basic/Targets.cpp +@@ -4535,6 +4535,7 @@ class SparcV9TargetInfo : public SparcTargetInfo { + LongDoubleWidth = 128; + LongDoubleAlign = 128; + LongDoubleFormat = &llvm::APFloat::IEEEquad; ++ MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + } + + virtual void getTargetDefines(const LangOptions &Opts, diff --git a/contrib/llvm/patches/patch-r262264-llvm-r200453-sparc.diff b/contrib/llvm/patches/patch-r262264-llvm-r200453-sparc.diff new file mode 100644 index 0000000..2c4470c --- /dev/null +++ b/contrib/llvm/patches/patch-r262264-llvm-r200453-sparc.diff @@ -0,0 +1,91 @@ +Pull in r200453 from upstream llvm trunk (by Jakob Stoklund Olesen): + + Implement SPARCv9 atomic_swap_64 with a pseudo. + + The SWAP instruction only exists in a 32-bit variant, but the 64-bit + atomic swap can be implemented in terms of CASX, like the other atomic + rmw primitives. + +Introduced here: http://svn.freebsd.org/changeset/base/262264 + +Index: lib/Target/Sparc/SparcInstr64Bit.td +=================================================================== +--- lib/Target/Sparc/SparcInstr64Bit.td ++++ lib/Target/Sparc/SparcInstr64Bit.td +@@ -463,6 +463,14 @@ defm ATOMIC_LOAD_MAX : AtomicRMW<atomic_load_max_ + defm ATOMIC_LOAD_UMIN : AtomicRMW<atomic_load_umin_32, atomic_load_umin_64>; + defm ATOMIC_LOAD_UMAX : AtomicRMW<atomic_load_umax_32, atomic_load_umax_64>; + ++// There is no 64-bit variant of SWAP, so use a pseudo. ++let usesCustomInserter = 1, hasCtrlDep = 1, mayLoad = 1, mayStore = 1, ++ Defs = [ICC], Predicates = [Is64Bit] in ++def ATOMIC_SWAP_64 : Pseudo<(outs I64Regs:$rd), ++ (ins ptr_rc:$addr, I64Regs:$rs2), "", ++ [(set i64:$rd, ++ (atomic_swap_64 iPTR:$addr, i64:$rs2))]>; ++ + // Global addresses, constant pool entries + let Predicates = [Is64Bit] in { + +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -1498,7 +1498,7 @@ SparcTargetLowering::SparcTargetLowering(TargetMac + + if (Subtarget->is64Bit()) { + setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i64, Legal); +- setOperationAction(ISD::ATOMIC_SWAP, MVT::i64, Expand); ++ setOperationAction(ISD::ATOMIC_SWAP, MVT::i64, Legal); + setOperationAction(ISD::ATOMIC_LOAD, MVT::i64, Custom); + setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Custom); + } +@@ -2885,6 +2885,9 @@ SparcTargetLowering::EmitInstrWithCustomInserter(M + case SP::ATOMIC_LOAD_NAND_64: + return expandAtomicRMW(MI, BB, SP::ANDXrr); + ++ case SP::ATOMIC_SWAP_64: ++ return expandAtomicRMW(MI, BB, 0); ++ + case SP::ATOMIC_LOAD_MAX_32: + return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_G); + case SP::ATOMIC_LOAD_MAX_64: +@@ -3023,7 +3026,8 @@ SparcTargetLowering::expandAtomicRMW(MachineInstr + + // Build the loop block. + unsigned ValReg = MRI.createVirtualRegister(ValueRC); +- unsigned UpdReg = MRI.createVirtualRegister(ValueRC); ++ // Opcode == 0 means try to write Rs2Reg directly (ATOMIC_SWAP). ++ unsigned UpdReg = (Opcode ? MRI.createVirtualRegister(ValueRC) : Rs2Reg); + + BuildMI(LoopMBB, DL, TII.get(SP::PHI), ValReg) + .addReg(Val0Reg).addMBB(MBB) +@@ -3035,7 +3039,7 @@ SparcTargetLowering::expandAtomicRMW(MachineInstr + BuildMI(LoopMBB, DL, TII.get(SP::CMPrr)).addReg(ValReg).addReg(Rs2Reg); + BuildMI(LoopMBB, DL, TII.get(Opcode), UpdReg) + .addReg(ValReg).addReg(Rs2Reg).addImm(CondCode); +- } else { ++ } else if (Opcode) { + BuildMI(LoopMBB, DL, TII.get(Opcode), UpdReg) + .addReg(ValReg).addReg(Rs2Reg); + } +Index: test/CodeGen/SPARC/atomics.ll +=================================================================== +--- test/CodeGen/SPARC/atomics.ll ++++ test/CodeGen/SPARC/atomics.ll +@@ -62,6 +62,15 @@ entry: + ret i32 %b + } + ++; CHECK-LABEL: test_swap_i64 ++; CHECK: casx [%o1], ++ ++define i64 @test_swap_i64(i64 %a, i64* %ptr) { ++entry: ++ %b = atomicrmw xchg i64* %ptr, i64 42 monotonic ++ ret i64 %b ++} ++ + ; CHECK-LABEL: test_load_add_32 + ; CHECK: membar + ; CHECK: add [[V:%[gilo][0-7]]], %o1, [[U:%[gilo][0-7]]] diff --git a/contrib/llvm/patches/patch-r262265-llvm-r201718-sparc.diff b/contrib/llvm/patches/patch-r262265-llvm-r201718-sparc.diff new file mode 100644 index 0000000..d9ca427 --- /dev/null +++ b/contrib/llvm/patches/patch-r262265-llvm-r201718-sparc.diff @@ -0,0 +1,40 @@ +Pull in r201718 from upstream llvm trunk (by Roman Divacky): + + Expand 64bit {SHL,SHR,SRA}_PARTS on sparcv9. + +Introduced here: http://svn.freebsd.org/changeset/base/262265 + +Index: test/CodeGen/SPARC/parts.ll +=================================================================== +--- test/CodeGen/SPARC/parts.ll ++++ test/CodeGen/SPARC/parts.ll +@@ -0,0 +1,14 @@ ++; RUN: llc < %s -march=sparcv9 | FileCheck %s ++ ++; CHECK-LABEL: test ++; CHECK: srl %i1, 0, %o2 ++; CHECK-NEXT: or %g0, %i2, %o0 ++; CHECK-NEXT: call __ashlti3 ++; CHECK-NEXT: or %g0, %i3, %o1 ++; CHECK-NEXT: or %g0, %o0, %i0 ++ ++define i128 @test(i128 %a, i128 %b) { ++entry: ++ %tmp = shl i128 %b, %a ++ ret i128 %tmp ++} +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -1554,6 +1554,10 @@ SparcTargetLowering::SparcTargetLowering(TargetMac + + setOperationAction(ISD::UMULO, MVT::i64, Custom); + setOperationAction(ISD::SMULO, MVT::i64, Custom); ++ ++ setOperationAction(ISD::SHL_PARTS, MVT::i64, Expand); ++ setOperationAction(ISD::SRA_PARTS, MVT::i64, Expand); ++ setOperationAction(ISD::SRL_PARTS, MVT::i64, Expand); + } + + // VASTART needs to be custom lowered to use the VarArgsFrameIndex. diff --git a/contrib/llvm/patches/patch-r262303-enable-ppc-integrated-as.diff b/contrib/llvm/patches/patch-r262303-enable-ppc-integrated-as.diff new file mode 100644 index 0000000..3d2e107 --- /dev/null +++ b/contrib/llvm/patches/patch-r262303-enable-ppc-integrated-as.diff @@ -0,0 +1,25 @@ +Pull in r197521 from upstream clang trunk (by Roman Divacky): + + Use the integrated assembler by default on FreeBSD/ppc and ppc64. + +Introduced here: http://svn.freebsd.org/changeset/base/262303 + +Index: tools/clang/lib/Driver/ToolChains.h +=================================================================== +--- tools/clang/lib/Driver/ToolChains.h ++++ tools/clang/lib/Driver/ToolChains.h +@@ -512,8 +512,13 @@ class LLVM_LIBRARY_VISIBILITY FreeBSD : public Gen + virtual void + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; ++ virtual bool IsIntegratedAssemblerDefault() const { ++ if (getTriple().getArch() == llvm::Triple::ppc || ++ getTriple().getArch() == llvm::Triple::ppc64) ++ return true; ++ return Generic_ELF::IsIntegratedAssemblerDefault(); ++ } + +- + virtual bool UseSjLjExceptions() const; + protected: + virtual Tool *buildAssembler() const; diff --git a/contrib/llvm/patches/patch-r262415-llvm-r201994-sparc.diff b/contrib/llvm/patches/patch-r262415-llvm-r201994-sparc.diff new file mode 100644 index 0000000..4f9b916 --- /dev/null +++ b/contrib/llvm/patches/patch-r262415-llvm-r201994-sparc.diff @@ -0,0 +1,49 @@ +Pull in r201994 from upstream llvm trunk (by Benjamin Kramer): + + SPARC: Implement TRAP lowering. Matches what GCC emits. + +Introduced here: http://svn.freebsd.org/changeset/base/262415 + +Index: lib/Target/Sparc/SparcInstrInfo.td +=================================================================== +--- lib/Target/Sparc/SparcInstrInfo.td ++++ lib/Target/Sparc/SparcInstrInfo.td +@@ -312,6 +312,9 @@ let hasSideEffects = 1, mayStore = 1 in { + [(flushw)]>; + } + ++let isBarrier = 1, isTerminator = 1, rd = 0b1000, rs1 = 0, simm13 = 5 in ++ def TA5 : F3_2<0b10, 0b111010, (outs), (ins), "ta 5", [(trap)]>; ++ + let rd = 0 in + def UNIMP : F2_1<0b000, (outs), (ins i32imm:$val), + "unimp $val", []>; +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -1565,6 +1565,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMac + // VAARG needs to be lowered to not do unaligned accesses for doubles. + setOperationAction(ISD::VAARG , MVT::Other, Custom); + ++ setOperationAction(ISD::TRAP , MVT::Other, Legal); ++ + // Use the default implementation. + setOperationAction(ISD::VACOPY , MVT::Other, Expand); + setOperationAction(ISD::VAEND , MVT::Other, Expand); +Index: test/CodeGen/SPARC/trap.ll +=================================================================== +--- test/CodeGen/SPARC/trap.ll ++++ test/CodeGen/SPARC/trap.ll +@@ -0,0 +1,11 @@ ++; RUN: llc -mtriple=sparc-linux-gnu < %s -show-mc-encoding | FileCheck %s ++ ++define void @test1() { ++ tail call void @llvm.trap() ++ unreachable ++ ++; CHECK-LABEL: test1: ++; CHECK: ta 5 ! encoding: [0x91,0xd0,0x20,0x05] ++} ++ ++declare void @llvm.trap() diff --git a/contrib/llvm/patches/patch-r262460-llvm-r202059-sparc.diff b/contrib/llvm/patches/patch-r262460-llvm-r202059-sparc.diff new file mode 100644 index 0000000..e683e33 --- /dev/null +++ b/contrib/llvm/patches/patch-r262460-llvm-r202059-sparc.diff @@ -0,0 +1,62 @@ +Pull in r202059 from upstream clang trunk (by Roman Divacky): + + Implement getDwarfEHStackPointer() and initDwarfEHRegSizeTable() for sparcv9. + +Introduced here: http://svn.freebsd.org/changeset/base/262460 + +Index: tools/clang/lib/CodeGen/TargetInfo.cpp +=================================================================== +--- tools/clang/lib/CodeGen/TargetInfo.cpp ++++ tools/clang/lib/CodeGen/TargetInfo.cpp +@@ -5435,10 +5435,51 @@ class SparcV9TargetCodeGenInfo : public TargetCode + public: + SparcV9TargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(new SparcV9ABIInfo(CGT)) {} ++ ++ int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const { ++ return 14; ++ } ++ ++ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, ++ llvm::Value *Address) const; + }; + } // end anonymous namespace + ++bool ++SparcV9TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, ++ llvm::Value *Address) const { ++ // This is calculated from the LLVM and GCC tables and verified ++ // against gcc output. AFAIK all ABIs use the same encoding. + ++ CodeGen::CGBuilderTy &Builder = CGF.Builder; ++ ++ llvm::IntegerType *i8 = CGF.Int8Ty; ++ llvm::Value *Four8 = llvm::ConstantInt::get(i8, 4); ++ llvm::Value *Eight8 = llvm::ConstantInt::get(i8, 8); ++ ++ // 0-31: the 8-byte general-purpose registers ++ AssignToArrayRange(Builder, Address, Eight8, 0, 31); ++ ++ // 32-63: f0-31, the 4-byte floating-point registers ++ AssignToArrayRange(Builder, Address, Four8, 32, 63); ++ ++ // Y = 64 ++ // PSR = 65 ++ // WIM = 66 ++ // TBR = 67 ++ // PC = 68 ++ // NPC = 69 ++ // FSR = 70 ++ // CSR = 71 ++ AssignToArrayRange(Builder, Address, Eight8, 64, 71); ++ ++ // 72-87: d0-15, the 8-byte floating-point registers ++ AssignToArrayRange(Builder, Address, Eight8, 72, 87); ++ ++ return false; ++} ++ ++ + //===----------------------------------------------------------------------===// + // Xcore ABI Implementation + //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/patches/patch-r262535-clang-r202177-sparc.diff b/contrib/llvm/patches/patch-r262535-clang-r202177-sparc.diff new file mode 100644 index 0000000..00514eb --- /dev/null +++ b/contrib/llvm/patches/patch-r262535-clang-r202177-sparc.diff @@ -0,0 +1,84 @@ +Pull in r202177 from upstream clang trunk (by Roman Divacky): + + Give sparcv9 the ability to set the target cpu. Change it from accepting + -march which doesnt exist on sparc gcc to -mcpu. While here adjust a + few tests to not write an unused temporary file. + +Introduced here: http://svn.freebsd.org/changeset/base/262535 + +Index: tools/clang/lib/Basic/Targets.cpp +=================================================================== +--- tools/clang/lib/Basic/Targets.cpp ++++ tools/clang/lib/Basic/Targets.cpp +@@ -4552,6 +4552,22 @@ class SparcV9TargetInfo : public SparcTargetInfo { + Builder.defineMacro("__sparcv9__"); + } + } ++ ++ virtual bool setCPU(const std::string &Name) { ++ bool CPUKnown = llvm::StringSwitch<bool>(Name) ++ .Case("v9", true) ++ .Case("ultrasparc", true) ++ .Case("ultrasparc3", true) ++ .Case("niagara", true) ++ .Case("niagara2", true) ++ .Case("niagara3", true) ++ .Case("niagara4", true) ++ .Default(false); ++ ++ // No need to store the CPU yet. There aren't any CPU-specific ++ // macros to define. ++ return CPUKnown; ++ } + }; + + } // end anonymous namespace. +Index: tools/clang/lib/Driver/Tools.cpp +=================================================================== +--- tools/clang/lib/Driver/Tools.cpp ++++ tools/clang/lib/Driver/Tools.cpp +@@ -1373,7 +1373,8 @@ static std::string getCPUName(const ArgList &Args, + } + + case llvm::Triple::sparc: +- if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) ++ case llvm::Triple::sparcv9: ++ if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + return A->getValue(); + return ""; + +Index: tools/clang/test/Driver/freebsd.c +=================================================================== +--- tools/clang/test/Driver/freebsd.c ++++ tools/clang/test/Driver/freebsd.c +@@ -59,13 +59,13 @@ + // CHECK-MIPSEL: "{{[^" ]*}}ld{{[^" ]*}}" + // CHECK-MIPSEL: "-dynamic-linker" "{{.*}}/libexec/ld-elf.so.1" + // CHECK-MIPSEL-NOT: "--hash-style={{gnu|both}}" +-// RUN: %clang %s -### -o %t.o 2>&1 \ ++// RUN: %clang %s -### 2>&1 \ + // RUN: -target mips64-unknown-freebsd10.0 \ + // RUN: | FileCheck --check-prefix=CHECK-MIPS64 %s + // CHECK-MIPS64: "{{[^" ]*}}ld{{[^" ]*}}" + // CHECK-MIPS64: "-dynamic-linker" "{{.*}}/libexec/ld-elf.so.1" + // CHECK-MIPS64-NOT: "--hash-style={{gnu|both}}" +-// RUN: %clang %s -### -o %t.o 2>&1 \ ++// RUN: %clang %s -### 2>&1 \ + // RUN: -target mips64el-unknown-freebsd10.0 \ + // RUN: | FileCheck --check-prefix=CHECK-MIPS64EL %s + // CHECK-MIPS64EL: "{{[^" ]*}}ld{{[^" ]*}}" +@@ -97,12 +97,12 @@ + // CHECK-NORMAL: crt1.o + // CHECK-NORMAL: crtbegin.o + +-// RUN: %clang %s -### -o %t.o -target arm-unknown-freebsd10.0 2>&1 \ ++// RUN: %clang %s -### -target arm-unknown-freebsd10.0 2>&1 \ + // RUN: | FileCheck --check-prefix=CHECK-ARM %s + // CHECK-ARM: clang{{.*}}" "-cc1"{{.*}}" "-fsjlj-exceptions" + // CHECK-ARM: as{{.*}}" "-mfpu=softvfp"{{.*}}"-matpcs" + +-// RUN: %clang %s -### -o %t.o -target arm-gnueabi-freebsd10.0 2>&1 \ ++// RUN: %clang %s -### -target arm-gnueabi-freebsd10.0 2>&1 \ + // RUN: | FileCheck --check-prefix=CHECK-ARM-EABI %s + // CHECK-ARM-EABI-NOT: clang{{.*}}" "-cc1"{{.*}}" "-fsjlj-exceptions" + // CHECK-ARM-EABI: as{{.*}}" "-mfpu=softvfp" "-meabi=5" diff --git a/contrib/llvm/patches/patch-r262536-clang-r202179-sparc.diff b/contrib/llvm/patches/patch-r262536-clang-r202179-sparc.diff new file mode 100644 index 0000000..5912dac --- /dev/null +++ b/contrib/llvm/patches/patch-r262536-clang-r202179-sparc.diff @@ -0,0 +1,22 @@ +Pull in r202179 from upstream clang trunk (by Roman Divacky): + + Pass the sparc architecture variant to the assembler. + +Introduced here: http://svn.freebsd.org/changeset/base/262536 + +Index: tools/clang/lib/Driver/Tools.cpp +=================================================================== +--- tools/clang/lib/Driver/Tools.cpp ++++ tools/clang/lib/Driver/Tools.cpp +@@ -5788,6 +5788,11 @@ void freebsd::Assemble::ConstructJob(Compilation & + } + } else if (getToolChain().getArch() == llvm::Triple::sparc || + getToolChain().getArch() == llvm::Triple::sparcv9) { ++ if (getToolChain().getArch() == llvm::Triple::sparc) ++ CmdArgs.push_back("-Av8plusa"); ++ else ++ CmdArgs.push_back("-Av9a"); ++ + Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, + options::OPT_fpic, options::OPT_fno_pic, + options::OPT_fPIE, options::OPT_fno_PIE, diff --git a/contrib/llvm/patches/patch-r262582-llvm-r202422-sparc.diff b/contrib/llvm/patches/patch-r262582-llvm-r202422-sparc.diff new file mode 100644 index 0000000..589dd47 --- /dev/null +++ b/contrib/llvm/patches/patch-r262582-llvm-r202422-sparc.diff @@ -0,0 +1,89 @@ +Pull in r202422 from upstream llvm trunk (by Roman Divacky): + + Lower FNEG just like FABS to fneg[ds] and fmov[ds], thus avoiding + expensive libcall. Also, Qp_neg is not implemented on at least + FreeBSD. This is also what gcc is doing. + +Introduced here: http://svn.freebsd.org/changeset/base/262582 + +Index: lib/Target/Sparc/SparcISelLowering.cpp +=================================================================== +--- lib/Target/Sparc/SparcISelLowering.cpp ++++ lib/Target/Sparc/SparcISelLowering.cpp +@@ -2643,24 +2643,16 @@ static SDValue LowerF128Store(SDValue Op, Selectio + &OutChains[0], 2); + } + +-static SDValue LowerFNEG(SDValue Op, SelectionDAG &DAG, +- const SparcTargetLowering &TLI, +- bool is64Bit) { +- if (Op.getValueType() == MVT::f64) +- return LowerF64Op(Op, DAG, ISD::FNEG); +- if (Op.getValueType() == MVT::f128) +- return TLI.LowerF128Op(Op, DAG, ((is64Bit) ? "_Qp_neg" : "_Q_neg"), 1); +- return Op; +-} ++static SDValue LowerFNEGorFABS(SDValue Op, SelectionDAG &DAG, bool isV9) { ++ assert((Op.getOpcode() == ISD::FNEG || Op.getOpcode() == ISD::FABS) && "invalid"); + +-static SDValue LowerFABS(SDValue Op, SelectionDAG &DAG, bool isV9) { + if (Op.getValueType() == MVT::f64) +- return LowerF64Op(Op, DAG, ISD::FABS); ++ return LowerF64Op(Op, DAG, Op.getOpcode()); + if (Op.getValueType() != MVT::f128) + return Op; + +- // Lower fabs on f128 to fabs on f64 +- // fabs f128 => fabs f64:sub_even64, fmov f64:sub_odd64 ++ // Lower fabs/fneg on f128 to fabs/fneg on f64 ++ // fabs/fneg f128 => fabs/fneg f64:sub_even64, fmov f64:sub_odd64 + + SDLoc dl(Op); + SDValue SrcReg128 = Op.getOperand(0); +@@ -2671,7 +2663,7 @@ static SDValue LowerF128Store(SDValue Op, Selectio + if (isV9) + Hi64 = DAG.getNode(Op.getOpcode(), dl, MVT::f64, Hi64); + else +- Hi64 = LowerF64Op(Hi64, DAG, ISD::FABS); ++ Hi64 = LowerF64Op(Hi64, DAG, Op.getOpcode()); + + SDValue DstReg128 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, + dl, MVT::f128), 0); +@@ -2792,7 +2784,6 @@ SDValue SparcTargetLowering:: + LowerOperation(SDValue Op, SelectionDAG &DAG) const { + + bool hasHardQuad = Subtarget->hasHardQuad(); +- bool is64Bit = Subtarget->is64Bit(); + bool isV9 = Subtarget->isV9(); + + switch (Op.getOpcode()) { +@@ -2835,8 +2826,8 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) cons + getLibcallName(RTLIB::DIV_F128), 2); + case ISD::FSQRT: return LowerF128Op(Op, DAG, + getLibcallName(RTLIB::SQRT_F128),1); +- case ISD::FNEG: return LowerFNEG(Op, DAG, *this, is64Bit); +- case ISD::FABS: return LowerFABS(Op, DAG, isV9); ++ case ISD::FABS: ++ case ISD::FNEG: return LowerFNEGorFABS(Op, DAG, isV9); + case ISD::FP_EXTEND: return LowerF128_FPEXTEND(Op, DAG, *this); + case ISD::FP_ROUND: return LowerF128_FPROUND(Op, DAG, *this); + case ISD::ADDC: +Index: test/CodeGen/SPARC/fp128.ll +=================================================================== +--- test/CodeGen/SPARC/fp128.ll ++++ test/CodeGen/SPARC/fp128.ll +@@ -232,3 +232,14 @@ entry: + store i32 %3, i32* %4, align 8 + ret void + } ++ ++; SOFT-LABEL: f128_neg ++; SOFT: fnegs ++ ++define void @f128_neg(fp128* noalias sret %scalar.result, fp128* byval %a) { ++entry: ++ %0 = load fp128* %a, align 8 ++ %1 = fsub fp128 0xL00000000000000008000000000000000, %0 ++ store fp128 %1, fp128* %scalar.result, align 8 ++ ret void ++} diff --git a/contrib/llvm/patches/patch-r262611-llvm-r196874-fix-invalid-pwd-crash.diff b/contrib/llvm/patches/patch-r262611-llvm-r196874-fix-invalid-pwd-crash.diff new file mode 100644 index 0000000..587693d --- /dev/null +++ b/contrib/llvm/patches/patch-r262611-llvm-r196874-fix-invalid-pwd-crash.diff @@ -0,0 +1,76 @@ +Pull in r196874 from upstream llvm trunk (by Andrew Trick): + + Fix a crash that occurs when PWD is invalid. + + MCJIT needs to be able to run in hostile environments, even when PWD + is invalid. There's no need to crash MCJIT in this case. + + The obvious fix is to simply leave MCContext's CompilationDir empty + when PWD can't be determined. This way, MCJIT clients, + and other clients that link with LLVM don?\226?\128?\153t need a valid working directory. + + If we do want to guarantee valid CompilationDir, that should be done + only for clients of getCompilationDir(). This is as simple as checking + for an empty string. + + The only current use of getCompilationDir is EmitGenDwarfInfo, which + won?\226?\128?\153t conceivably run with an invalid working dir. However, in the + purely hypothetically and untestable case that this happens, the + AT_comp_dir will be omitted from the compilation_unit DIE. + +Introduced here: http://svn.freebsd.org/changeset/base/262611 + +Index: include/llvm/MC/MCContext.h +=================================================================== +--- include/llvm/MC/MCContext.h ++++ include/llvm/MC/MCContext.h +@@ -278,6 +278,7 @@ namespace llvm { + /// This can be overridden by clients which want to control the reported + /// compilation directory and have it be something other than the current + /// working directory. ++ /// Returns an empty string if the current directory cannot be determined. + StringRef getCompilationDir() const { return CompilationDir; } + + /// \brief Set the compilation directory for DW_AT_comp_dir +Index: lib/MC/MCContext.cpp +=================================================================== +--- lib/MC/MCContext.cpp ++++ lib/MC/MCContext.cpp +@@ -47,8 +47,8 @@ MCContext::MCContext(const MCAsmInfo *mai, const M + AllowTemporaryLabels(true), DwarfCompileUnitID(0), AutoReset(DoAutoReset) { + + error_code EC = llvm::sys::fs::current_path(CompilationDir); +- assert(!EC && "Could not determine the current directory"); +- (void)EC; ++ if (EC) ++ CompilationDir.clear(); + + MachOUniquingMap = 0; + ELFUniquingMap = 0; +Index: lib/MC/MCDwarf.cpp +=================================================================== +--- lib/MC/MCDwarf.cpp ++++ lib/MC/MCDwarf.cpp +@@ -467,7 +467,8 @@ static void EmitGenDwarfAbbrev(MCStreamer *MCOS) { + EmitAbbrev(MCOS, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr); + EmitAbbrev(MCOS, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr); + EmitAbbrev(MCOS, dwarf::DW_AT_name, dwarf::DW_FORM_string); +- EmitAbbrev(MCOS, dwarf::DW_AT_comp_dir, dwarf::DW_FORM_string); ++ if (!context.getCompilationDir().empty()) ++ EmitAbbrev(MCOS, dwarf::DW_AT_comp_dir, dwarf::DW_FORM_string); + StringRef DwarfDebugFlags = context.getDwarfDebugFlags(); + if (!DwarfDebugFlags.empty()) + EmitAbbrev(MCOS, dwarf::DW_AT_APPLE_flags, dwarf::DW_FORM_string); +@@ -643,8 +644,10 @@ static void EmitGenDwarfInfo(MCStreamer *MCOS, + MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string. + + // AT_comp_dir, the working directory the assembly was done in. +- MCOS->EmitBytes(context.getCompilationDir()); +- MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string. ++ if (!context.getCompilationDir().empty()) { ++ MCOS->EmitBytes(context.getCompilationDir()); ++ MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string. ++ } + + // AT_APPLE_flags, the command line arguments of the assembler tool. + StringRef DwarfDebugFlags = context.getDwarfDebugFlags(); diff --git a/contrib/llvm/patches/patch-r262809-clang-r203007-destructor-calling-conv.diff b/contrib/llvm/patches/patch-r262809-clang-r203007-destructor-calling-conv.diff new file mode 100644 index 0000000..5341b8b --- /dev/null +++ b/contrib/llvm/patches/patch-r262809-clang-r203007-destructor-calling-conv.diff @@ -0,0 +1,61 @@ +Pull in r203007 from upstream clang trunk (by Rafael Espindola): + + Don't produce an alias between destructors with different calling conventions. + + Fixes pr19007. + +Introduced here: http://svn.freebsd.org/changeset/base/262809 + +Index: tools/clang/lib/CodeGen/CGCXX.cpp +=================================================================== +--- tools/clang/lib/CodeGen/CGCXX.cpp ++++ tools/clang/lib/CodeGen/CGCXX.cpp +@@ -92,7 +92,13 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(c + if (!ClassLayout.getBaseClassOffset(UniqueBase).isZero()) + return true; + ++ // Give up if the calling conventions don't match. We could update the call, ++ // but it is probably not worth it. + const CXXDestructorDecl *BaseD = UniqueBase->getDestructor(); ++ if (BaseD->getType()->getAs<FunctionType>()->getCallConv() != ++ D->getType()->getAs<FunctionType>()->getCallConv()) ++ return true; ++ + return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base), + GlobalDecl(BaseD, Dtor_Base), + false); +Index: tools/clang/test/CodeGenCXX/ctor-dtor-alias.cpp +=================================================================== +--- tools/clang/test/CodeGenCXX/ctor-dtor-alias.cpp ++++ tools/clang/test/CodeGenCXX/ctor-dtor-alias.cpp +@@ -1,5 +1,5 @@ +-// RUN: %clang_cc1 %s -triple x86_64-linux -emit-llvm -o - -mconstructor-aliases -O1 -disable-llvm-optzns | FileCheck %s +-// RUN: %clang_cc1 %s -triple x86_64-linux -emit-llvm -o - -mconstructor-aliases | FileCheck --check-prefix=NOOPT %s ++// RUN: %clang_cc1 %s -triple i686-linux -emit-llvm -o - -mconstructor-aliases -O1 -disable-llvm-optzns | FileCheck %s ++// RUN: %clang_cc1 %s -triple i686-linux -emit-llvm -o - -mconstructor-aliases | FileCheck --check-prefix=NOOPT %s + + // RUN: %clang_cc1 -cc1 -triple x86_64--netbsd -emit-llvm \ + // RUN: -mconstructor-aliases -O2 %s -o - | FileCheck --check-prefix=CHECK-RAUW %s +@@ -133,6 +133,22 @@ namespace test8 { + zed foo; + } + ++namespace test9 { ++struct foo { ++ __attribute__((stdcall)) ~foo() { ++ } ++}; ++ ++struct bar : public foo {}; ++ ++void zed() { ++ // Test that we produce a call to bar's destructor. We used to call foo's, but ++ // it has a different calling conversion. ++ // CHECK-DAG: call void @_ZN5test93barD2Ev ++ bar ptr; ++} ++} ++ + // CHECK-RAUW: @_ZTV1C = linkonce_odr unnamed_addr constant [4 x i8*] [{{[^@]*}}@_ZTI1C {{[^@]*}}@_ZN1CD2Ev {{[^@]*}}@_ZN1CD0Ev {{[^@]*}}] + // r194296 replaced C::~C with B::~B without emitting the later. + diff --git a/contrib/llvm/patches/patch-r263048-clang-r203624-fix-CC-aliases.diff b/contrib/llvm/patches/patch-r263048-clang-r203624-fix-CC-aliases.diff new file mode 100644 index 0000000..1aac8cb --- /dev/null +++ b/contrib/llvm/patches/patch-r263048-clang-r203624-fix-CC-aliases.diff @@ -0,0 +1,24 @@ +Pull in r203624 from upstream clang trunk (by Hans Wennborg): + + Be case sensitive when determining driver mode based on argv[0] except on Windows + + This narrows the impact of r188833 after Dimitry pointed out that it's good to be + able to tell the difference between 'cc' and 'CC'. + +Introduced here: http://svn.freebsd.org/changeset/base/263048 + +Index: tools/clang/tools/driver/driver.cpp +=================================================================== +--- tools/clang/tools/driver/driver.cpp ++++ tools/clang/tools/driver/driver.cpp +@@ -229,8 +229,10 @@ static void ParseProgName(SmallVectorImpl<const ch + { "++", "--driver-mode=g++" }, + }; + std::string ProgName(llvm::sys::path::stem(ArgVector[0])); ++#ifdef _WIN32 + std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(), + toLowercase); ++#endif + StringRef ProgNameRef(ProgName); + StringRef Prefix; + diff --git a/contrib/llvm/patches/patch-r263312-llvm-r169939-inline-asm-with-realign.diff b/contrib/llvm/patches/patch-r263312-llvm-r169939-inline-asm-with-realign.diff new file mode 100644 index 0000000..f92dd3a --- /dev/null +++ b/contrib/llvm/patches/patch-r263312-llvm-r169939-inline-asm-with-realign.diff @@ -0,0 +1,338 @@ +Pull in r196939 from upstream llvm trunk (by Reid Kleckner): + + Reland "Fix miscompile of MS inline assembly with stack realignment" + + This re-lands commit r196876, which was reverted in r196879. + + The tests have been fixed to pass on platforms with a stack alignment + larger than 4. + + Update to clang side tests will land shortly. + +Introduced here: http://svn.freebsd.org/changeset/base/263312 + +Index: test/CodeGen/X86/inline-asm-stack-realign2.ll +=================================================================== +--- test/CodeGen/X86/inline-asm-stack-realign2.ll ++++ test/CodeGen/X86/inline-asm-stack-realign2.ll +@@ -0,0 +1,15 @@ ++; RUN: not llc -mtriple=i686-pc-win32 < %s 2>&1 | FileCheck %s ++ ++; We don't currently support realigning the stack and adjusting the stack ++; pointer in inline asm. This can even happen in GNU asm. ++ ++; CHECK: Stack realignment in presence of dynamic stack adjustments is not supported with inline assembly ++ ++define i32 @foo() { ++entry: ++ %r = alloca i32, align 16 ++ store i32 -1, i32* %r, align 16 ++ call void asm sideeffect "push %esi\0A\09xor %esi, %esi\0A\09mov %esi, $0\0A\09pop %esi", "=*m,~{flags},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"(i32* %r) ++ %0 = load i32* %r, align 16 ++ ret i32 %0 ++} +Index: test/CodeGen/X86/inline-asm-stack-realign.ll +=================================================================== +--- test/CodeGen/X86/inline-asm-stack-realign.ll ++++ test/CodeGen/X86/inline-asm-stack-realign.ll +@@ -0,0 +1,16 @@ ++; RUN: not llc -mtriple=i686-pc-win32 < %s 2>&1 | FileCheck %s ++ ++; We don't currently support realigning the stack and adjusting the stack ++; pointer in inline asm. This commonly happens in MS inline assembly using ++; push and pop. ++ ++; CHECK: Stack realignment in presence of dynamic stack adjustments is not supported with inline assembly ++ ++define i32 @foo() { ++entry: ++ %r = alloca i32, align 16 ++ store i32 -1, i32* %r, align 16 ++ call void asm sideeffect inteldialect "push esi\0A\09xor esi, esi\0A\09mov dword ptr $0, esi\0A\09pop esi", "=*m,~{flags},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"(i32* %r) ++ %0 = load i32* %r, align 16 ++ ret i32 %0 ++} +Index: test/CodeGen/X86/ms-inline-asm.ll +=================================================================== +--- test/CodeGen/X86/ms-inline-asm.ll ++++ test/CodeGen/X86/ms-inline-asm.ll +@@ -5,7 +5,6 @@ entry: + %0 = tail call i32 asm sideeffect inteldialect "mov eax, $1\0A\09mov $0, eax", "=r,r,~{eax},~{dirflag},~{fpsr},~{flags}"(i32 1) nounwind + ret i32 %0 + ; CHECK: t1 +-; CHECK: movl %esp, %ebp + ; CHECK: {{## InlineAsm Start|#APP}} + ; CHECK: .intel_syntax + ; CHECK: mov eax, ecx +@@ -19,7 +18,6 @@ entry: + call void asm sideeffect inteldialect "mov eax, $$1", "~{eax},~{dirflag},~{fpsr},~{flags}"() nounwind + ret void + ; CHECK: t2 +-; CHECK: movl %esp, %ebp + ; CHECK: {{## InlineAsm Start|#APP}} + ; CHECK: .intel_syntax + ; CHECK: mov eax, 1 +@@ -34,7 +32,6 @@ entry: + call void asm sideeffect inteldialect "mov eax, DWORD PTR [$0]", "*m,~{eax},~{dirflag},~{fpsr},~{flags}"(i32* %V.addr) nounwind + ret void + ; CHECK: t3 +-; CHECK: movl %esp, %ebp + ; CHECK: {{## InlineAsm Start|#APP}} + ; CHECK: .intel_syntax + ; CHECK: mov eax, DWORD PTR {{[[esp]}} +@@ -56,7 +53,6 @@ entry: + %0 = load i32* %b1, align 4 + ret i32 %0 + ; CHECK: t18 +-; CHECK: movl %esp, %ebp + ; CHECK: {{## InlineAsm Start|#APP}} + ; CHECK: .intel_syntax + ; CHECK: lea ebx, foo +@@ -76,7 +72,6 @@ entry: + call void asm sideeffect inteldialect "call $0", "r,~{dirflag},~{fpsr},~{flags}"(void ()* @t19_helper) nounwind + ret void + ; CHECK-LABEL: t19: +-; CHECK: movl %esp, %ebp + ; CHECK: movl ${{_?}}t19_helper, %eax + ; CHECK: {{## InlineAsm Start|#APP}} + ; CHECK: .intel_syntax +@@ -95,7 +90,6 @@ entry: + %0 = load i32** %res, align 4 + ret i32* %0 + ; CHECK-LABEL: t30: +-; CHECK: movl %esp, %ebp + ; CHECK: {{## InlineAsm Start|#APP}} + ; CHECK: .intel_syntax + ; CHECK: lea edi, dword ptr [{{_?}}results] +@@ -103,8 +97,31 @@ entry: + ; CHECK: {{## InlineAsm End|#NO_APP}} + ; CHECK: {{## InlineAsm Start|#APP}} + ; CHECK: .intel_syntax +-; CHECK: mov dword ptr [esi], edi ++; CHECK: mov dword ptr [esp], edi + ; CHECK: .att_syntax + ; CHECK: {{## InlineAsm End|#NO_APP}} +-; CHECK: movl (%esi), %eax ++; CHECK: movl (%esp), %eax + } ++ ++; Stack realignment plus MS inline asm that does *not* adjust the stack is no ++; longer an error. ++ ++define i32 @t31() { ++entry: ++ %val = alloca i32, align 64 ++ store i32 -1, i32* %val, align 64 ++ call void asm sideeffect inteldialect "mov dword ptr $0, esp", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* %val) #1 ++ %sp = load i32* %val, align 64 ++ ret i32 %sp ++; CHECK-LABEL: t31: ++; CHECK: pushl %ebp ++; CHECK: movl %esp, %ebp ++; CHECK: andl $-64, %esp ++; CHECK: {{## InlineAsm Start|#APP}} ++; CHECK: .intel_syntax ++; CHECK: mov dword ptr [esp], esp ++; CHECK: .att_syntax ++; CHECK: {{## InlineAsm End|#NO_APP}} ++; CHECK: movl (%esp), %eax ++; CHECK: ret ++} +Index: include/llvm/CodeGen/MachineFrameInfo.h +=================================================================== +--- include/llvm/CodeGen/MachineFrameInfo.h ++++ include/llvm/CodeGen/MachineFrameInfo.h +@@ -223,6 +223,10 @@ class MachineFrameInfo { + /// Whether the "realign-stack" option is on. + bool RealignOption; + ++ /// True if the function includes inline assembly that adjusts the stack ++ /// pointer. ++ bool HasInlineAsmWithSPAdjust; ++ + const TargetFrameLowering *getFrameLowering() const; + public: + explicit MachineFrameInfo(const TargetMachine &TM, bool RealignOpt) +@@ -451,6 +455,10 @@ class MachineFrameInfo { + bool hasCalls() const { return HasCalls; } + void setHasCalls(bool V) { HasCalls = V; } + ++ /// Returns true if the function contains any stack-adjusting inline assembly. ++ bool hasInlineAsmWithSPAdjust() const { return HasInlineAsmWithSPAdjust; } ++ void setHasInlineAsmWithSPAdjust(bool B) { HasInlineAsmWithSPAdjust = B; } ++ + /// getMaxCallFrameSize - Return the maximum size of a call frame that must be + /// allocated for an outgoing function call. This is only available if + /// CallFrameSetup/Destroy pseudo instructions are used by the target, and +Index: include/llvm/CodeGen/MachineFunction.h +=================================================================== +--- include/llvm/CodeGen/MachineFunction.h ++++ include/llvm/CodeGen/MachineFunction.h +@@ -131,8 +131,8 @@ class MachineFunction { + /// about the control flow of such functions. + bool ExposesReturnsTwice; + +- /// True if the function includes MS-style inline assembly. +- bool HasMSInlineAsm; ++ /// True if the function includes any inline assembly. ++ bool HasInlineAsm; + + MachineFunction(const MachineFunction &) LLVM_DELETED_FUNCTION; + void operator=(const MachineFunction&) LLVM_DELETED_FUNCTION; +@@ -218,15 +218,14 @@ class MachineFunction { + ExposesReturnsTwice = B; + } + +- /// Returns true if the function contains any MS-style inline assembly. +- bool hasMSInlineAsm() const { +- return HasMSInlineAsm; ++ /// Returns true if the function contains any inline assembly. ++ bool hasInlineAsm() const { ++ return HasInlineAsm; + } + +- /// Set a flag that indicates that the function contains MS-style inline +- /// assembly. +- void setHasMSInlineAsm(bool B) { +- HasMSInlineAsm = B; ++ /// Set a flag that indicates that the function contains inline assembly. ++ void setHasInlineAsm(bool B) { ++ HasInlineAsm = B; + } + + /// getInfo - Keep track of various per-function pieces of information for +Index: lib/Target/X86/X86FrameLowering.cpp +=================================================================== +--- lib/Target/X86/X86FrameLowering.cpp ++++ lib/Target/X86/X86FrameLowering.cpp +@@ -50,7 +50,7 @@ bool X86FrameLowering::hasFP(const MachineFunction + return (MF.getTarget().Options.DisableFramePointerElim(MF) || + RegInfo->needsStackRealignment(MF) || + MFI->hasVarSizedObjects() || +- MFI->isFrameAddressTaken() || MF.hasMSInlineAsm() || ++ MFI->isFrameAddressTaken() || MFI->hasInlineAsmWithSPAdjust() || + MF.getInfo<X86MachineFunctionInfo>()->getForceFramePointer() || + MMI.callsUnwindInit() || MMI.callsEHReturn()); + } +Index: lib/Target/X86/X86RegisterInfo.cpp +=================================================================== +--- lib/Target/X86/X86RegisterInfo.cpp ++++ lib/Target/X86/X86RegisterInfo.cpp +@@ -347,6 +347,12 @@ BitVector X86RegisterInfo::getReservedRegs(const M + "Stack realignment in presence of dynamic allocas is not supported with" + "this calling convention."); + ++ // FIXME: Do a proper analysis of the inline asm to see if it actually ++ // conflicts with the base register we chose. ++ if (MF.hasInlineAsm()) ++ report_fatal_error("Stack realignment in presence of dynamic stack " ++ "adjustments is not supported with inline assembly."); ++ + for (MCSubRegIterator I(getBaseRegister(), this, /*IncludeSelf=*/true); + I.isValid(); ++I) + Reserved.set(*I); +@@ -403,18 +409,15 @@ bool X86RegisterInfo::hasBasePointer(const Machine + if (!EnableBasePointer) + return false; + +- // When we need stack realignment and there are dynamic allocas, we can't +- // reference off of the stack pointer, so we reserve a base pointer. +- // +- // This is also true if the function contain MS-style inline assembly. We +- // do this because if any stack changes occur in the inline assembly, e.g., +- // "pusha", then any C local variable or C argument references in the +- // inline assembly will be wrong because the SP is not properly tracked. +- if ((needsStackRealignment(MF) && MFI->hasVarSizedObjects()) || +- MF.hasMSInlineAsm()) +- return true; +- +- return false; ++ // When we need stack realignment, we can't address the stack from the frame ++ // pointer. When we have dynamic allocas or stack-adjusting inline asm, we ++ // can't address variables from the stack pointer. MS inline asm can ++ // reference locals while also adjusting the stack pointer. When we can't ++ // use both the SP and the FP, we need a separate base pointer register. ++ bool CantUseFP = needsStackRealignment(MF); ++ bool CantUseSP = ++ MFI->hasVarSizedObjects() || MFI->hasInlineAsmWithSPAdjust(); ++ return CantUseFP && CantUseSP; + } + + bool X86RegisterInfo::canRealignStack(const MachineFunction &MF) const { +Index: lib/MC/MCParser/AsmParser.cpp +=================================================================== +--- lib/MC/MCParser/AsmParser.cpp ++++ lib/MC/MCParser/AsmParser.cpp +@@ -4192,6 +4192,11 @@ bool AsmParser::parseMSInlineAsm( + AsmStrRewrites.push_back(AsmRewrite(AOK_Input, Start, SymName.size())); + } + } ++ ++ // Consider implicit defs to be clobbers. Think of cpuid and push. ++ const uint16_t *ImpDefs = Desc.getImplicitDefs(); ++ for (unsigned I = 0, E = Desc.getNumImplicitDefs(); I != E; ++I) ++ ClobberRegs.push_back(ImpDefs[I]); + } + + // Set the number of Outputs and Inputs. +Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +=================================================================== +--- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp ++++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +@@ -851,12 +851,20 @@ void RegsForValue::AddInlineAsmOperands(unsigned C + SDValue Res = DAG.getTargetConstant(Flag, MVT::i32); + Ops.push_back(Res); + ++ unsigned SP = TLI.getStackPointerRegisterToSaveRestore(); + for (unsigned Value = 0, Reg = 0, e = ValueVTs.size(); Value != e; ++Value) { + unsigned NumRegs = TLI.getNumRegisters(*DAG.getContext(), ValueVTs[Value]); + MVT RegisterVT = RegVTs[Value]; + for (unsigned i = 0; i != NumRegs; ++i) { + assert(Reg < Regs.size() && "Mismatch in # registers expected"); +- Ops.push_back(DAG.getRegister(Regs[Reg++], RegisterVT)); ++ unsigned TheReg = Regs[Reg++]; ++ Ops.push_back(DAG.getRegister(TheReg, RegisterVT)); ++ ++ // Notice if we clobbered the stack pointer. Yes, inline asm can do this. ++ if (TheReg == SP && Code == InlineAsm::Kind_Clobber) { ++ MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); ++ MFI->setHasInlineAsmWithSPAdjust(true); ++ } + } + } + } +Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +=================================================================== +--- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp ++++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +@@ -428,7 +428,9 @@ bool SelectionDAGISel::runOnMachineFunction(Machin + + SDB->init(GFI, *AA, LibInfo); + +- MF->setHasMSInlineAsm(false); ++ MF->setHasInlineAsm(false); ++ MF->getFrameInfo()->setHasInlineAsmWithSPAdjust(false); ++ + SelectAllBasicBlocks(Fn); + + // If the first basic block in the function has live ins that need to be +@@ -511,7 +513,7 @@ bool SelectionDAGISel::runOnMachineFunction(Machin + for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); I != E; + ++I) { + +- if (MFI->hasCalls() && MF->hasMSInlineAsm()) ++ if (MFI->hasCalls() && MF->hasInlineAsm()) + break; + + const MachineBasicBlock *MBB = I; +@@ -522,8 +524,8 @@ bool SelectionDAGISel::runOnMachineFunction(Machin + II->isStackAligningInlineAsm()) { + MFI->setHasCalls(true); + } +- if (II->isMSInlineAsm()) { +- MF->setHasMSInlineAsm(true); ++ if (II->isInlineAsm()) { ++ MF->setHasInlineAsm(true); + } + } + } diff --git a/contrib/llvm/patches/patch-r263312-llvm-r196940-update-inline-asm-test.diff b/contrib/llvm/patches/patch-r263312-llvm-r196940-update-inline-asm-test.diff new file mode 100644 index 0000000..6ce56cb --- /dev/null +++ b/contrib/llvm/patches/patch-r263312-llvm-r196940-update-inline-asm-test.diff @@ -0,0 +1,78 @@ +Pull in r196940 from upstream clang trunk (by Reid Kleckner): + + Update clang MS inline asm tests for r196939 + +Introduced here: http://svn.freebsd.org/changeset/base/263312 + +Index: tools/clang/test/CodeGen/ms-inline-asm.cpp +=================================================================== +--- tools/clang/test/CodeGen/ms-inline-asm.cpp ++++ tools/clang/test/CodeGen/ms-inline-asm.cpp +@@ -97,7 +97,7 @@ void test5() { + // CHECK: [[Y:%.*]] = alloca i32 + int x, y; + __asm push y +- // CHECK: call void asm sideeffect inteldialect "push dword ptr $0", "=*m,~{dirflag},~{fpsr},~{flags}"(i32* [[Y]]) ++ // CHECK: call void asm sideeffect inteldialect "push dword ptr $0", "=*m,~{esp},~{dirflag},~{fpsr},~{flags}"(i32* [[Y]]) + __asm call T5<int>::create<float> + // CHECK: call void asm sideeffect inteldialect "call $0", "r,~{dirflag},~{fpsr},~{flags}"(i32 (float)* @_ZN2T5IiE6createIfEEiT_) + __asm mov x, eax +Index: tools/clang/test/CodeGen/ms-inline-asm.c +=================================================================== +--- tools/clang/test/CodeGen/ms-inline-asm.c ++++ tools/clang/test/CodeGen/ms-inline-asm.c +@@ -77,7 +77,7 @@ void t9() { + pop ebx + } + // CHECK: t9 +-// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{dirflag},~{fpsr},~{flags}"() ++// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"() + } + + unsigned t10(void) { +@@ -211,7 +211,7 @@ void t21() { + __asm pop ebx + } + // CHECK: t21 +-// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{dirflag},~{fpsr},~{flags}"() ++// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, $$0x07\0A\09pop ebx", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"() + } + + extern void t22_helper(int x); +@@ -227,7 +227,7 @@ void t22() { + __asm pop ebx + } + // CHECK: t22 +-// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, esp", "~{ebx},~{dirflag},~{fpsr},~{flags}"() ++// CHECK: call void asm sideeffect inteldialect "push ebx\0A\09mov ebx, esp", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"() + // CHECK: call void @t22_helper + // CHECK: call void asm sideeffect inteldialect "mov esp, ebx\0A\09pop ebx", "~{ebx},~{esp},~{dirflag},~{fpsr},~{flags}"() + } +@@ -268,13 +268,14 @@ void t26() { + __asm __emit 0a2h + __asm __EMIT 0a2h + __asm popad ++// FIXME: These all need to be merged into the same asm blob. + // CHECK: t26 +-// CHECK: call void asm sideeffect inteldialect "pushad", "~{dirflag},~{fpsr},~{flags}"() ++// CHECK: call void asm sideeffect inteldialect "pushad", "~{esp},~{dirflag},~{fpsr},~{flags}"() + // CHECK: call void asm sideeffect inteldialect "mov eax, $$0", "~{eax},~{dirflag},~{fpsr},~{flags}"() + // CHECK: call void asm sideeffect inteldialect ".byte 0fh", "~{dirflag},~{fpsr},~{flags}"() + // CHECK: call void asm sideeffect inteldialect ".byte 0a2h", "~{dirflag},~{fpsr},~{flags}"() + // CHECK: call void asm sideeffect inteldialect ".byte 0a2h", "~{dirflag},~{fpsr},~{flags}"() +-// CHECK: call void asm sideeffect inteldialect "popad", "~{dirflag},~{fpsr},~{flags}"() ++// CHECK: call void asm sideeffect inteldialect "popad", "~{eax},~{ebp},~{ebx},~{ecx},~{edi},~{edx},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"() + } + + void t27() { +@@ -323,8 +324,8 @@ void t31() { + __asm pushad + __asm popad + // CHECK: t31 +-// CHECK: call void asm sideeffect inteldialect "pushad", "~{dirflag},~{fpsr},~{flags}"() +-// CHECK: call void asm sideeffect inteldialect "popad", "~{dirflag},~{fpsr},~{flags}"() ++// CHECK: call void asm sideeffect inteldialect "pushad", "~{esp},~{dirflag},~{fpsr},~{flags}"() ++// CHECK: call void asm sideeffect inteldialect "popad", "~{eax},~{ebp},~{ebx},~{ecx},~{edi},~{edx},~{esi},~{esp},~{dirflag},~{fpsr},~{flags}"() + } + + void t32() { diff --git a/contrib/llvm/patches/patch-r263312-llvm-r196986-allow-realign-alloca.diff b/contrib/llvm/patches/patch-r263312-llvm-r196986-allow-realign-alloca.diff new file mode 100644 index 0000000..2c0b759 --- /dev/null +++ b/contrib/llvm/patches/patch-r263312-llvm-r196986-allow-realign-alloca.diff @@ -0,0 +1,98 @@ +Pull in r196986 from upstream llvm trunk (by Reid Kleckner): + + Revert the backend fatal error from r196939 + + The combination of inline asm, stack realignment, and dynamic allocas + turns out to be too common to reject out of hand. + + ASan inserts empy inline asm fragments and uses aligned allocas. + Compiling any trivial function containing a dynamic alloca with ASan is + enough to trigger the check. + + XFAIL the test cases that would be miscompiled and add one that uses the + relevant functionality. + +Introduced here: http://svn.freebsd.org/changeset/base/263312 + +Index: lib/Target/X86/X86RegisterInfo.cpp +=================================================================== +--- lib/Target/X86/X86RegisterInfo.cpp ++++ lib/Target/X86/X86RegisterInfo.cpp +@@ -347,12 +347,6 @@ BitVector X86RegisterInfo::getReservedRegs(const M + "Stack realignment in presence of dynamic allocas is not supported with" + "this calling convention."); + +- // FIXME: Do a proper analysis of the inline asm to see if it actually +- // conflicts with the base register we chose. +- if (MF.hasInlineAsm()) +- report_fatal_error("Stack realignment in presence of dynamic stack " +- "adjustments is not supported with inline assembly."); +- + for (MCSubRegIterator I(getBaseRegister(), this, /*IncludeSelf=*/true); + I.isValid(); ++I) + Reserved.set(*I); +Index: test/CodeGen/X86/inline-asm-stack-realign3.ll +=================================================================== +--- test/CodeGen/X86/inline-asm-stack-realign3.ll ++++ test/CodeGen/X86/inline-asm-stack-realign3.ll +@@ -0,0 +1,29 @@ ++; RUN: llc -march=x86 < %s | FileCheck %s ++ ++declare void @bar(i32* %junk) ++ ++define i32 @foo(i1 %cond) { ++entry: ++ %r = alloca i32, align 128 ++ store i32 -1, i32* %r, align 128 ++ br i1 %cond, label %doit, label %skip ++ ++doit: ++ call void asm sideeffect "xor %ecx, %ecx\0A\09mov %ecx, $0", "=*m,~{ecx},~{flags}"(i32* %r) ++ %junk = alloca i32 ++ call void @bar(i32* %junk) ++ br label %skip ++ ++skip: ++ %0 = load i32* %r, align 128 ++ ret i32 %0 ++} ++ ++; CHECK-LABEL: foo: ++; CHECK: pushl %ebp ++; CHECK: andl $-128, %esp ++; CHECK: xor %ecx, %ecx ++; CHECK-NEXT: mov %ecx, (%esi) ++; CHECK: movl (%esi), %eax ++; CHECK: popl %ebp ++; CHECK: ret +Index: test/CodeGen/X86/inline-asm-stack-realign.ll +=================================================================== +--- test/CodeGen/X86/inline-asm-stack-realign.ll ++++ test/CodeGen/X86/inline-asm-stack-realign.ll +@@ -1,8 +1,8 @@ + ; RUN: not llc -mtriple=i686-pc-win32 < %s 2>&1 | FileCheck %s + +-; We don't currently support realigning the stack and adjusting the stack +-; pointer in inline asm. This commonly happens in MS inline assembly using +-; push and pop. ++; FIXME: This is miscompiled due to our unconditional use of ESI as the base ++; pointer. ++; XFAIL: + + ; CHECK: Stack realignment in presence of dynamic stack adjustments is not supported with inline assembly + +Index: test/CodeGen/X86/inline-asm-stack-realign2.ll +=================================================================== +--- test/CodeGen/X86/inline-asm-stack-realign2.ll ++++ test/CodeGen/X86/inline-asm-stack-realign2.ll +@@ -1,7 +1,8 @@ + ; RUN: not llc -mtriple=i686-pc-win32 < %s 2>&1 | FileCheck %s + +-; We don't currently support realigning the stack and adjusting the stack +-; pointer in inline asm. This can even happen in GNU asm. ++; FIXME: This is miscompiled due to our unconditional use of ESI as the base ++; pointer. ++; XFAIL: + + ; CHECK: Stack realignment in presence of dynamic stack adjustments is not supported with inline assembly + diff --git a/contrib/llvm/patches/patch-r263312-llvm-r202930-fix-alloca-esi-clobber.diff b/contrib/llvm/patches/patch-r263312-llvm-r202930-fix-alloca-esi-clobber.diff new file mode 100644 index 0000000..b4017c9 --- /dev/null +++ b/contrib/llvm/patches/patch-r263312-llvm-r202930-fix-alloca-esi-clobber.diff @@ -0,0 +1,263 @@ +Pull in r202930 from upstream llvm trunk (by Hans Wennborg): + + Check for dynamic allocas and inline asm that clobbers sp before building + selection dag (PR19012) + + In X86SelectionDagInfo::EmitTargetCodeForMemcpy we check with MachineFrameInfo + to make sure that ESI isn't used as a base pointer register before we choose to + emit rep movs (which clobbers esi). + + The problem is that MachineFrameInfo wouldn't know about dynamic allocas or + inline asm that clobbers the stack pointer until SelectionDAGBuilder has + encountered them. + + This patch fixes the problem by checking for such things when building the + FunctionLoweringInfo. + + Differential Revision: http://llvm-reviews.chandlerc.com/D2954 + +Introduced here: http://svn.freebsd.org/changeset/base/263312 + +Index: lib/CodeGen/MachineFunction.cpp +=================================================================== +--- lib/CodeGen/MachineFunction.cpp ++++ lib/CodeGen/MachineFunction.cpp +@@ -525,13 +525,14 @@ int MachineFrameInfo::CreateSpillStackObject(uint6 + /// variable sized object is created, whether or not the index returned is + /// actually used. + /// +-int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment) { ++int MachineFrameInfo::CreateVariableSizedObject(unsigned Alignment, ++ const AllocaInst *Alloca) { + HasVarSizedObjects = true; + Alignment = + clampStackAlignment(!getFrameLowering()->isStackRealignable() || + !RealignOption, + Alignment, getFrameLowering()->getStackAlignment()); +- Objects.push_back(StackObject(0, Alignment, 0, false, false, true, 0)); ++ Objects.push_back(StackObject(0, Alignment, 0, false, false, true, Alloca)); + ensureMaxAlignment(Alignment); + return (int)Objects.size()-NumFixedObjects-1; + } +Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +=================================================================== +--- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp ++++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +@@ -419,7 +419,7 @@ bool SelectionDAGISel::runOnMachineFunction(Machin + SplitCriticalSideEffectEdges(const_cast<Function&>(Fn), this); + + CurDAG->init(*MF, TTI, TLI); +- FuncInfo->set(Fn, *MF); ++ FuncInfo->set(Fn, *MF, CurDAG); + + if (UseMBPI && OptLevel != CodeGenOpt::None) + FuncInfo->BPI = &getAnalysis<BranchProbabilityInfo>(); +@@ -429,7 +429,6 @@ bool SelectionDAGISel::runOnMachineFunction(Machin + SDB->init(GFI, *AA, LibInfo); + + MF->setHasInlineAsm(false); +- MF->getFrameInfo()->setHasInlineAsmWithSPAdjust(false); + + SelectAllBasicBlocks(Fn); + +Index: lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +=================================================================== +--- lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp ++++ lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +@@ -33,6 +33,7 @@ + #include "llvm/Support/ErrorHandling.h" + #include "llvm/Support/MathExtras.h" + #include "llvm/Target/TargetInstrInfo.h" ++#include "llvm/Target/TargetFrameLowering.h" + #include "llvm/Target/TargetLowering.h" + #include "llvm/Target/TargetOptions.h" + #include "llvm/Target/TargetRegisterInfo.h" +@@ -55,7 +56,8 @@ static bool isUsedOutsideOfDefiningBlock(const Ins + return false; + } + +-void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf) { ++void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, ++ SelectionDAG *DAG) { + const TargetLowering *TLI = TM.getTargetLowering(); + + Fn = &fn; +@@ -100,6 +102,43 @@ static bool isUsedOutsideOfDefiningBlock(const Ins + for (; BB != EB; ++BB) + for (BasicBlock::const_iterator I = BB->begin(), E = BB->end(); + I != E; ++I) { ++ // Look for dynamic allocas. ++ if (const AllocaInst *AI = dyn_cast<AllocaInst>(I)) { ++ if (!AI->isStaticAlloca()) { ++ unsigned Align = std::max( ++ (unsigned)TLI->getDataLayout()->getPrefTypeAlignment( ++ AI->getAllocatedType()), ++ AI->getAlignment()); ++ unsigned StackAlign = TM.getFrameLowering()->getStackAlignment(); ++ if (Align <= StackAlign) ++ Align = 0; ++ // Inform the Frame Information that we have variable-sized objects. ++ MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1, AI); ++ } ++ } ++ ++ // Look for inline asm that clobbers the SP register. ++ if (isa<CallInst>(I) || isa<InvokeInst>(I)) { ++ ImmutableCallSite CS(I); ++ if (const InlineAsm *IA = dyn_cast<InlineAsm>(CS.getCalledValue())) { ++ unsigned SP = TLI->getStackPointerRegisterToSaveRestore(); ++ std::vector<TargetLowering::AsmOperandInfo> Ops = ++ TLI->ParseConstraints(CS); ++ for (size_t I = 0, E = Ops.size(); I != E; ++I) { ++ TargetLowering::AsmOperandInfo &Op = Ops[I]; ++ if (Op.Type == InlineAsm::isClobber) { ++ // Clobbers don't have SDValue operands, hence SDValue(). ++ TLI->ComputeConstraintToUse(Op, SDValue(), DAG); ++ std::pair<unsigned, const TargetRegisterClass*> PhysReg = ++ TLI->getRegForInlineAsmConstraint(Op.ConstraintCode, ++ Op.ConstraintVT); ++ if (PhysReg.first == SP) ++ MF->getFrameInfo()->setHasInlineAsmWithSPAdjust(true); ++ } ++ } ++ } ++ } ++ + // Mark values used outside their block as exported, by allocating + // a virtual register for them. + if (isUsedOutsideOfDefiningBlock(I)) +Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +=================================================================== +--- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp ++++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +@@ -860,10 +860,10 @@ void RegsForValue::AddInlineAsmOperands(unsigned C + unsigned TheReg = Regs[Reg++]; + Ops.push_back(DAG.getRegister(TheReg, RegisterVT)); + +- // Notice if we clobbered the stack pointer. Yes, inline asm can do this. + if (TheReg == SP && Code == InlineAsm::Kind_Clobber) { +- MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); +- MFI->setHasInlineAsmWithSPAdjust(true); ++ // If we clobbered the stack pointer, MFI should know about it. ++ assert(DAG.getMachineFunction().getFrameInfo()-> ++ hasInlineAsmWithSPAdjust()); + } + } + } +@@ -3378,9 +3378,7 @@ void SelectionDAGBuilder::visitAlloca(const Alloca + setValue(&I, DSA); + DAG.setRoot(DSA.getValue(1)); + +- // Inform the Frame Information that we have just allocated a variable-sized +- // object. +- FuncInfo.MF->getFrameInfo()->CreateVariableSizedObject(Align ? Align : 1); ++ assert(FuncInfo.MF->getFrameInfo()->hasVarSizedObjects()); + } + + void SelectionDAGBuilder::visitLoad(const LoadInst &I) { +Index: test/CodeGen/X86/stack-align-memcpy.ll +=================================================================== +--- test/CodeGen/X86/stack-align-memcpy.ll ++++ test/CodeGen/X86/stack-align-memcpy.ll +@@ -2,6 +2,9 @@ + + %struct.foo = type { [88 x i8] } + ++declare void @bar(i8* nocapture, %struct.foo* align 4 byval) nounwind ++declare void @baz(i8*) nounwind ++ + ; PR15249 + ; We can't use rep;movsl here because it clobbers the base pointer in %esi. + define void @test1(%struct.foo* nocapture %x, i32 %y) nounwind { +@@ -15,4 +18,26 @@ define void @test1(%struct.foo* nocapture %x, i32 + ; CHECK-NOT: rep;movsl + } + +-declare void @bar(i8* nocapture, %struct.foo* align 4 byval) nounwind ++; PR19012 ++; Also don't clobber %esi if the dynamic alloca comes after the memcpy. ++define void @test2(%struct.foo* nocapture %x, i32 %y, i8* %z) nounwind { ++ call void @bar(i8* %z, %struct.foo* align 4 byval %x) ++ %dynalloc = alloca i8, i32 %y, align 1 ++ call void @baz(i8* %dynalloc) ++ ret void ++ ++; CHECK-LABEL: test2: ++; CHECK: movl %esp, %esi ++; CHECK-NOT: rep;movsl ++} ++ ++; Check that we do use rep movs if we make the alloca static. ++define void @test3(%struct.foo* nocapture %x, i32 %y, i8* %z) nounwind { ++ call void @bar(i8* %z, %struct.foo* align 4 byval %x) ++ %statalloc = alloca i8, i32 8, align 1 ++ call void @baz(i8* %statalloc) ++ ret void ++ ++; CHECK-LABEL: test3: ++; CHECK: rep;movsl ++} +Index: test/CodeGen/X86/inline-asm-sp-clobber-memcpy.ll +=================================================================== +--- test/CodeGen/X86/inline-asm-sp-clobber-memcpy.ll ++++ test/CodeGen/X86/inline-asm-sp-clobber-memcpy.ll +@@ -0,0 +1,17 @@ ++; RUN: llc < %s -force-align-stack -mtriple i386-apple-darwin -mcpu=i486 | FileCheck %s ++ ++%struct.foo = type { [88 x i8] } ++ ++declare void @bar(i8* nocapture, %struct.foo* align 4 byval) nounwind ++ ++; PR19012 ++; Don't clobber %esi if we have inline asm that clobbers %esp. ++define void @test1(%struct.foo* nocapture %x, i32 %y, i8* %z) nounwind { ++ call void @bar(i8* %z, %struct.foo* align 4 byval %x) ++ call void asm sideeffect inteldialect "xor esp, esp", "=*m,~{flags},~{esp},~{esp},~{dirflag},~{fpsr},~{flags}"(i8* %z) ++ ret void ++ ++; CHECK-LABEL: test1: ++; CHECK: movl %esp, %esi ++; CHECK-NOT: rep;movsl ++} +Index: include/llvm/CodeGen/FunctionLoweringInfo.h +=================================================================== +--- include/llvm/CodeGen/FunctionLoweringInfo.h ++++ include/llvm/CodeGen/FunctionLoweringInfo.h +@@ -41,6 +41,7 @@ class MachineBasicBlock; + class MachineFunction; + class MachineModuleInfo; + class MachineRegisterInfo; ++class SelectionDAG; + class TargetLowering; + class Value; + +@@ -125,7 +126,7 @@ class FunctionLoweringInfo { + /// set - Initialize this FunctionLoweringInfo with the given Function + /// and its associated MachineFunction. + /// +- void set(const Function &Fn, MachineFunction &MF); ++ void set(const Function &Fn, MachineFunction &MF, SelectionDAG *DAG); + + /// clear - Clear out all the function-specific state. This returns this + /// FunctionLoweringInfo to an empty state, ready to be used for a +Index: include/llvm/CodeGen/MachineFrameInfo.h +=================================================================== +--- include/llvm/CodeGen/MachineFrameInfo.h ++++ include/llvm/CodeGen/MachineFrameInfo.h +@@ -244,6 +244,7 @@ class MachineFrameInfo { + LocalFrameSize = 0; + LocalFrameMaxAlign = 0; + UseLocalStackAllocationBlock = false; ++ HasInlineAsmWithSPAdjust = false; + } + + /// hasStackObjects - Return true if there are any stack objects in this +@@ -529,7 +530,7 @@ class MachineFrameInfo { + /// variable sized object is created, whether or not the index returned is + /// actually used. + /// +- int CreateVariableSizedObject(unsigned Alignment); ++ int CreateVariableSizedObject(unsigned Alignment, const AllocaInst *Alloca); + + /// getCalleeSavedInfo - Returns a reference to call saved info vector for the + /// current function. diff --git a/contrib/llvm/patches/patch-r263313-llvm-r203311-fix-sse1-oom.diff b/contrib/llvm/patches/patch-r263313-llvm-r203311-fix-sse1-oom.diff new file mode 100644 index 0000000..43efd12 --- /dev/null +++ b/contrib/llvm/patches/patch-r263313-llvm-r203311-fix-sse1-oom.diff @@ -0,0 +1,60 @@ +Pull in r203311 from upstream llvm trunk (by Arnold Schwaighofer): + + ISel: Make VSELECT selection terminate in cases where the condition type has to + be split and the result type widened. + + When the condition of a vselect has to be split it makes no sense widening the + vselect and thereby widening the condition. We end up in an endless loop of + widening (vselect result type) and splitting (condition mask type) doing this. + Instead, split both the condition and the vselect and widen the result. + + I ran this over the test suite with i686 and mattr=+sse and saw no regressions. + + Fixes PR18036. + +Introduced here: http://svn.freebsd.org/changeset/base/263313 + +Index: test/CodeGen/X86/sse1.ll +=================================================================== +--- test/CodeGen/X86/sse1.ll ++++ test/CodeGen/X86/sse1.ll +@@ -43,3 +43,17 @@ entry: + ; CHECK-NOT: shufps $16 + ; CHECK: ret + } ++ ++; We used to get stuck in type legalization for this example when lowering the ++; vselect. With SSE1 v4f32 is a legal type but v4i1 (or any vector integer type) ++; is not. We used to ping pong between splitting the vselect for the v4i ++; condition operand and widening the resulting vselect for the v4f32 result. ++; PR18036 ++ ++; CHECK-LABEL: vselect ++define <4 x float> @vselect(<4 x float>*%p, <4 x i32> %q) { ++entry: ++ %a1 = icmp eq <4 x i32> %q, zeroinitializer ++ %a14 = select <4 x i1> %a1, <4 x float> <float 1.000000e+00, float 2.000000e+00, float 3.000000e+00, float 4.000000e+0> , <4 x float> zeroinitializer ++ ret <4 x float> %a14 ++} +Index: lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +=================================================================== +--- lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp ++++ lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +@@ -2180,6 +2180,17 @@ SDValue DAGTypeLegalizer::WidenVecRes_SELECT(SDNod + if (getTypeAction(CondVT) == TargetLowering::TypeWidenVector) + Cond1 = GetWidenedVector(Cond1); + ++ // If we have to split the condition there is no point in widening the ++ // select. This would result in an cycle of widening the select -> ++ // widening the condition operand -> splitting the condition operand -> ++ // splitting the select -> widening the select. Instead split this select ++ // further and widen the resulting type. ++ if (getTypeAction(CondVT) == TargetLowering::TypeSplitVector) { ++ SDValue SplitSelect = SplitVecOp_VSELECT(N, 0); ++ SDValue Res = ModifyToType(SplitSelect, WidenVT); ++ return Res; ++ } ++ + if (Cond1.getValueType() != CondWidenVT) + Cond1 = ModifyToType(Cond1, CondWidenVT); + } |