diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -649,7 +649,7 @@ /// This emits linkage information about \p GVSym based on \p GV, if this is /// supported by the target. - void EmitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const; + virtual void EmitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const; /// Return the alignment for the specified \p GV. static Align getGVAlignment(const GlobalValue *GV, const DataLayout &DL, diff --git a/llvm/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h --- a/llvm/include/llvm/MC/MCAsmInfo.h +++ b/llvm/include/llvm/MC/MCAsmInfo.h @@ -93,6 +93,10 @@ /// constants into comdat sections. bool HasCOFFComdatConstants = false; + /// False if this is a XCOFF target that supports visibility attribute in + /// .global, .weak, .extern ,.comm. Default is true. + bool HasVisibilityDirective = true; + /// This is the maximum possible length of an instruction, which is needed to /// compute the size of an inline asm. Defaults to 4. unsigned MaxInstLength = 4; @@ -492,6 +496,7 @@ bool hasMachoTBSSDirective() const { return HasMachoTBSSDirective; } bool hasCOFFAssociativeComdats() const { return HasCOFFAssociativeComdats; } bool hasCOFFComdatConstants() const { return HasCOFFComdatConstants; } + bool hasVisibilityDirective() const { return HasVisibilityDirective; } /// Returns the maximum possible encoded instruction size in bytes. If \p STI /// is null, this should be the maximum size for any subtarget. diff --git a/llvm/include/llvm/MC/MCDirectives.h b/llvm/include/llvm/MC/MCDirectives.h --- a/llvm/include/llvm/MC/MCDirectives.h +++ b/llvm/include/llvm/MC/MCDirectives.h @@ -29,6 +29,7 @@ MCSA_ELF_TypeGnuUniqueObject, /// .type _foo, @gnu_unique_object MCSA_Global, ///< .globl MCSA_LGlobal, ///< .lglobl (XCOFF) + MCSA_Extern, ///< .extern (XCOFF) MCSA_Hidden, ///< .hidden (ELF) MCSA_IndirectSymbol, ///< .indirect_symbol (MachO) MCSA_Internal, ///< .internal (ELF) diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -566,6 +566,9 @@ MCSymbol *CsectSym, unsigned ByteAlignment); + virtual void EmitXCOFFSymbolAttrWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Attribute, + MCSymbolAttr Visibilitily); /// Emit an ELF .size directive. /// /// This corresponds to an assembler statement such as: diff --git a/llvm/include/llvm/MC/MCXCOFFStreamer.h b/llvm/include/llvm/MC/MCXCOFFStreamer.h --- a/llvm/include/llvm/MC/MCXCOFFStreamer.h +++ b/llvm/include/llvm/MC/MCXCOFFStreamer.h @@ -29,6 +29,9 @@ void EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, MCSymbol *CsectSym, unsigned ByteAlign) override; + void EmitXCOFFSymbolAttrWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Attribute, + MCSymbolAttr Visibilitily) override; }; } // end namespace llvm diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -665,7 +665,8 @@ // Print the 'header' of function. OutStreamer->SwitchSection(getObjFileLowering().SectionForGlobal(&F, TM)); - EmitVisibility(CurrentFnSym, F.getVisibility()); + if (MAI->hasVisibilityDirective()) + EmitVisibility(CurrentFnSym, F.getVisibility()); if (MAI->needsFunctionDescriptors() && F.getLinkage() != GlobalValue::InternalLinkage) @@ -1419,7 +1420,15 @@ continue; MCSymbol *Name = getSymbol(&F); - EmitVisibility(Name, V, false); + if (MAI->needsFunctionDescriptors()) { + // Get the function entry point symbol. + Name = OutContext.getOrCreateSymbol("." + Name->getName()); + } + + if (MAI->hasVisibilityDirective()) + EmitVisibility(Name, V, false); + else + EmitLinkage(&F, Name); } // Emit the remarks section contents. diff --git a/llvm/lib/MC/MCAsmInfoXCOFF.cpp b/llvm/lib/MC/MCAsmInfoXCOFF.cpp --- a/llvm/lib/MC/MCAsmInfoXCOFF.cpp +++ b/llvm/lib/MC/MCAsmInfoXCOFF.cpp @@ -16,6 +16,7 @@ IsLittleEndian = false; HasDotTypeDotSizeDirective = false; COMMDirectiveAlignmentIsInBytes = false; + HasVisibilityDirective = false; LCOMMDirectiveAlignmentType = LCOMM::Log2Alignment; UseDotAlignForAlignment = true; AsciiDirective = nullptr; // not supported diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/DebugInfo/CodeView/SymbolRecord.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAsmInfo.h" @@ -27,7 +28,9 @@ #include "llvm/MC/MCRegister.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSectionXCOFF.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbolXCOFF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormattedStream.h" @@ -169,6 +172,9 @@ void EmitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size, MCSymbol *CsectSym, unsigned ByteAlign) override; + void EmitXCOFFSymbolAttrWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Attribute, + MCSymbolAttr Visibilitily) override; void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; @@ -658,6 +664,9 @@ case MCSA_Hidden: OS << "\t.hidden\t"; break; case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break; case MCSA_Internal: OS << "\t.internal\t"; break; + case MCSA_Extern: + OS << "\t.extern\t"; + break; case MCSA_LazyReference: OS << "\t.lazy_reference\t"; break; case MCSA_Local: OS << "\t.local\t"; break; case MCSA_NoDeadStrip: @@ -785,6 +794,52 @@ EmitEOL(); } +void MCAsmStreamer::EmitXCOFFSymbolAttrWithVisibility( + MCSymbol *Symbol, MCSymbolAttr Attribute, MCSymbolAttr Visibilitily) { + + switch (Attribute) { + case MCSA_Global: + OS << MAI->getGlobalDirective(); + break; + case MCSA_Weak: + OS << MAI->getWeakDirective(); + break; + case MCSA_Extern: + OS << "\t.extern\t"; + break; + default: + EmitSymbolAttribute(Symbol, Attribute); + return; + } + + MCSymbolXCOFF *XCOFFSym = cast(Symbol); + + if (XCOFFSym->hasContainingCsect()) { + MCSymbolXCOFF *QualName = + XCOFFSym->getContainingCsect()->getQualNameSymbol(); + if (Symbol->getName() == QualName->getUnqualifiedName() && + XCOFFSym->getContainingCsect()->getMappingClass() != XCOFF::XMC_PR) + QualName->print(OS, MAI); + else + Symbol->print(OS, MAI); + } else + Symbol->print(OS, MAI); + + switch (Visibilitily) { + default: + break; + case MCSA_Hidden: + OS << " , hidden"; + break; + case MCSA_Protected: + OS << " , protected"; + break; + } + + EmitEOL(); + return; +} + void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { assert(MAI->hasDotTypeDotSizeDirective()); OS << "\t.size\t"; diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -1069,6 +1069,12 @@ unsigned ByteAlign) { llvm_unreachable("this directive only supported on XCOFF targets"); } +void MCStreamer::EmitXCOFFSymbolAttrWithVisibility(MCSymbol *Symbol, + MCSymbolAttr Attribute, + MCSymbolAttr Visibilitily) { + llvm_unreachable( + "The EmitXCOFFSymbolAttrWithVisibility only supported on XCOFF targets"); +} void MCStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} void MCStreamer::emitELFSymverDirective(StringRef AliasName, const MCSymbol *Aliasee) {} diff --git a/llvm/lib/MC/MCXCOFFStreamer.cpp b/llvm/lib/MC/MCXCOFFStreamer.cpp --- a/llvm/lib/MC/MCXCOFFStreamer.cpp +++ b/llvm/lib/MC/MCXCOFFStreamer.cpp @@ -34,6 +34,7 @@ switch (Attribute) { case MCSA_Global: + case MCSA_Extern: Symbol->setStorageClass(XCOFF::C_EXT); Symbol->setExternal(true); break; @@ -43,6 +44,13 @@ return true; } +void MCXCOFFStreamer::EmitXCOFFSymbolAttrWithVisibility( + MCSymbol *Symbol, MCSymbolAttr Attribute, MCSymbolAttr Visibilitily) { + EmitSymbolAttribute(Symbol, Attribute); + // Fixed me: Not implement Visibility on the object file. + // EmitSymbolAttribute(Symbol,Visibilitily); +} + void MCXCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { getAssembler().registerSymbol(*Symbol); diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp --- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp +++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp @@ -168,6 +168,8 @@ void EmitFunctionDescriptor() override; void EmitEndOfAsmFile(Module &) override; + + void EmitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const override; }; } // end anonymous namespace @@ -1579,6 +1581,45 @@ } } +void PPCAIXAsmPrinter::EmitLinkage(const GlobalValue *GV, + MCSymbol *GVSym) const { + GlobalValue::LinkageTypes Linkage = GV->getLinkage(); + GlobalValue::VisibilityTypes Visibiltiy = GV->getVisibility(); + MCSymbolAttr VisibilityAttr = MCSA_Invalid; + + switch (Visibiltiy) { + default: + break; + case GlobalValue::HiddenVisibility: + VisibilityAttr = MAI->getHiddenVisibilityAttr(); + break; + case GlobalValue::ProtectedVisibility: + VisibilityAttr = MAI->getProtectedVisibilityAttr(); + break; + } + + switch (Linkage) { + default: + AsmPrinter::EmitLinkage(GV, GVSym); + return; + case GlobalValue::ExternalLinkage: + // If external, declare as a global symbol: .globl _foo + if (GV->isDeclaration()) + OutStreamer->EmitXCOFFSymbolAttrWithVisibility(GVSym, MCSA_Extern, + VisibilityAttr); + else + OutStreamer->EmitXCOFFSymbolAttrWithVisibility(GVSym, MCSA_Global, + VisibilityAttr); + return; + case GlobalValue::InternalLinkage: + if (MAI->hasDotLGloblDirective()) + OutStreamer->EmitSymbolAttribute(GVSym, MCSA_LGlobal); + return; + } + + llvm_unreachable("Unknown linkage type!"); +} + void PPCAIXAsmPrinter::SetupMachineFunction(MachineFunction &MF) { // Get the function descriptor symbol. CurrentFnDescSym = getSymbol(&MF.getFunction()); diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -6901,10 +6901,10 @@ assert(IsPPC64 && "PPC32 should have split i64 values."); LLVM_FALLTHROUGH; case MVT::i1: - case MVT::i32: - State.AllocateStack(PtrByteSize, PtrByteSize); + case MVT::i32:{ + unsigned Offset = State.AllocateStack(PtrByteSize, PtrByteSize); + MVT RegVT = IsPPC64 ? MVT::i64 : MVT::i32; if (unsigned Reg = State.AllocateReg(IsPPC64 ? GPR_64 : GPR_32)) { - MVT RegVT = IsPPC64 ? MVT::i64 : MVT::i32; // Promote integers if needed. if (ValVT.getSizeInBits() < RegVT.getSizeInBits()) LocInfo = ArgFlags.isSExt() ? CCValAssign::LocInfo::SExt @@ -6912,38 +6912,39 @@ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, RegVT, LocInfo)); } else - report_fatal_error("Handling of placing parameters on the stack is " - "unimplemented!"); - return false; + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, RegVT, LocInfo)); + return false; + } case MVT::f32: case MVT::f64: { // Parameter save area (PSA) is reserved even if the float passes in fpr. const unsigned StoreSize = LocVT.getStoreSize(); // Floats are always 4-byte aligned in the PSA on AIX. // This includes f64 in 64-bit mode for ABI compatibility. - State.AllocateStack(IsPPC64 ? 8 : StoreSize, 4); - if (unsigned Reg = State.AllocateReg(FPR)) - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - else - report_fatal_error("Handling of placing parameters on the stack is " - "unimplemented!"); - - // AIX requires that GPRs are reserved for float arguments. - // Successfully reserved GPRs are only initialized for vararg calls. + const unsigned Offset = State.AllocateStack(IsPPC64 ? 8 : StoreSize, 4); + unsigned FReg = State.AllocateReg(FPR); + if (FReg) + State.addLoc(CCValAssign::getReg(ValNo, ValVT, FReg, LocVT, LocInfo)); + // GPRs or parameter save area memory must be reserved for float args. MVT RegVT = IsPPC64 ? MVT::i64 : MVT::i32; for (unsigned I = 0; I < StoreSize; I += PtrByteSize) { - if (unsigned Reg = State.AllocateReg(IsPPC64 ? GPR_64 : GPR_32)) { + if (unsigned Reg = State.AllocateReg(IsPPC64 ? GPR_64 : GPR_32)) { + assert(FReg && "An FPR should be available when a GPR is reserved."); if (State.isVarArg()) { + // Successfully reserved GPRs are only initialized for vararg calls. // Custom handling is required for: // f64 in PPC32 needs to be split into 2 GPRs. // f32 in PPC64 needs to occupy only lower 32 bits of 64-bit GPR. State.addLoc( CCValAssign::getCustomReg(ValNo, ValVT, Reg, RegVT, LocInfo)); } - } else if (State.isVarArg()) { - report_fatal_error("Handling of placing parameters on the stack is " - "unimplemented!"); + } else { + // There may be GPRs reserved for prior words, which only partially + // cover the argument. The full memory for the argument will be + // initialized either way. + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); + break; } } @@ -6993,13 +6994,14 @@ const SmallVectorImpl &Ins, const SDLoc &dl, SelectionDAG &DAG, SmallVectorImpl &InVals) const { + MachineFunction &MF = DAG.getMachineFunction(); + PPCFunctionInfo *FuncInfo = MF.getInfo(); + MachineFrameInfo &MFI = MF.getFrameInfo(); + EVT PtrVT = getPointerTy(MF.getDataLayout()); assert((CallConv == CallingConv::C || CallConv == CallingConv::Cold || CallConv == CallingConv::Fast) && "Unexpected calling convention!"); - if (isVarArg) - report_fatal_error("This call type is unimplemented on AIX."); - if (getTargetMachine().Options.GuaranteedTailCallOpt) report_fatal_error("Tail call support is unimplemented on AIX."); @@ -7011,28 +7013,31 @@ if (Subtarget.hasQPX()) report_fatal_error("QPX support is not supported on AIX."); + // Potential tail calls could cause overwriting of argument stack slots. + const bool IsImmutable = !(getTargetMachine().Options.GuaranteedTailCallOpt && + (CallConv == CallingConv::Fast)); const bool IsPPC64 = Subtarget.isPPC64(); const unsigned PtrByteSize = IsPPC64 ? 8 : 4; // Assign locations to all of the incoming arguments. SmallVector ArgLocs; - MachineFunction &MF = DAG.getMachineFunction(); CCState CCInfo(CallConv, isVarArg, MF, ArgLocs, *DAG.getContext()); - // Reserve space for the linkage area on the stack. const unsigned LinkageSize = Subtarget.getFrameLowering()->getLinkageSize(); - // On AIX a minimum of 8 words is saved to the parameter save area. - const unsigned MinParameterSaveArea = 8 * PtrByteSize; - CCInfo.AllocateStack(LinkageSize + MinParameterSaveArea, PtrByteSize); + CCInfo.AllocateStack(CCInfo.getNextStackOffset(), PtrByteSize); CCInfo.AnalyzeFormalArguments(Ins, CC_AIX); for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; SDValue ArgValue; - ISD::ArgFlagsTy Flags = Ins[i].Flags; + EVT ValVT = VA.getValVT(); + MVT LocVT = VA.getLocVT(); + // There are more ArgLocs than parameters. Get appropriate argument flag for + // each ArgLoc. + ISD::ArgFlagsTy Flags = Ins[VA.getValNo()].Flags; + if (VA.isRegLoc()) { - EVT ValVT = VA.getValVT(); - MVT LocVT = VA.getLocVT(); + if (!VA.needsCustom()) { MVT::SimpleValueType SVT = ValVT.getSimpleVT().SimpleTy; unsigned VReg = MF.addLiveIn(VA.getLocReg(), getRegClassForSVT(SVT, IsPPC64)); @@ -7042,27 +7047,98 @@ ArgValue = truncateScalarIntegerArg(Flags, ValVT, DAG, ArgValue, LocVT, dl); } + } + // Once all GPRs have been allocated, CC_AIX assigns FP arguments to + // memory and FP registers(if any remain free). Look forward and check + // whether the next ArgLoc has the same value number and skip it if + // does. CC_AIX also adds extra ArgLocs for FP arguments during a + // variadic function definition, we need to skip those as well. + if ((VA.getValVT() == MVT::f32 || VA.getValVT() == MVT::f64) && + (i + 1 != e)) { + if ((ArgLocs[i + 1].isMemLoc() || ArgLocs[i + 1].needsCustom())&& + (ArgLocs[i + 1].getValNo() == VA.getValNo())){ + ++i; + if (i + 1 !=e && !IsPPC64 && VA.getValVT() == MVT::f64){ + //Skip extra ArgLoc for f64 split into 2 in 32-bit mode. + if (ArgLocs[i + 1].needsCustom() || ArgLocs[i+1].getValNo() == VA.getValNo()) + ++i;}} + } + InVals.push_back(ArgValue); } else { - report_fatal_error("Handling of formal arguments on the stack is " - "unimplemented!"); + assert(VA.isMemLoc()); + // Get the extended size of the argument type in stack + unsigned ArgSize = VA.getLocVT().getStoreSize(); + // Get the actual size of the argument type + unsigned ObjSize = VA.getValVT().getStoreSize(); + unsigned CurArgOffset = VA.getLocMemOffset(); + // Stack objects in AIX are right justified. + CurArgOffset += ArgSize - ObjSize; + int FI = MFI.CreateFixedObject(PtrByteSize, LinkageSize + CurArgOffset, + IsImmutable); + SDValue FIN = DAG.getFrameIndex(FI, PtrVT); + // All arguments reserve stack space in the AIX ABI. + ArgValue = + DAG.getLoad(VA.getValVT(), dl, Chain, FIN, MachinePointerInfo()); + InVals.push_back(ArgValue); } } + // On AIX a minimum of 8 words is saved to the parameter save area. + const unsigned MinParameterSaveArea = 8 * PtrByteSize; // Area that is at least reserved in the caller of this function. - unsigned MinReservedArea = CCInfo.getNextStackOffset(); + unsigned MinReservedArea = + std::max(LinkageSize + CCInfo.getNextStackOffset(), + LinkageSize + MinParameterSaveArea); - // Set the size that is at least reserved in caller of this function. Tail - // call optimized function's reserved stack space needs to be aligned so - // that taking the difference between two stack areas will result in an - // aligned stack. + // Set the size that is at least reserved in caller of this function. Tail + // call optimized function's reserved stack space needs to be aligned so that + // taking the difference between two stack areas will result in an aligned + // stack. MinReservedArea = EnsureStackAlignment(Subtarget.getFrameLowering(), MinReservedArea); - PPCFunctionInfo *FuncInfo = MF.getInfo(); FuncInfo->setMinReservedArea(MinReservedArea); + SmallVector MemOps; + + if (isVarArg) { + static const MCPhysReg GPArgRegs[] = { + PPC::R3, PPC::R4, PPC::R5, PPC::R6, PPC::R7, PPC::R8, PPC::R9, PPC::R10, + }; + const unsigned NumGPArgRegs = array_lengthof(GPArgRegs); + + //Find unused GPRs + FuncInfo->setVarArgsNumGPR(CCInfo.getFirstUnallocated(GPArgRegs)); + //Set up the stack frame + FuncInfo->setVarArgsFrameIndex( + MFI.CreateStackObject(MinReservedArea, PtrByteSize, false)); + SDValue FIN = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), PtrVT); + + // The fixed integer arguments of a variadic function are stored to the + // VarArgsFrameIndex on the stack so that they may be loaded by + // dereferencing the result of va_next. + for (unsigned GPRIndex = 0; GPRIndex != NumGPArgRegs; ++GPRIndex) { + // Get an existing live-in vreg, or add a new one. + unsigned VReg = MF.getRegInfo().getLiveInVirtReg(GPArgRegs[GPRIndex]); + if (!VReg) + VReg = MF.addLiveIn(GPArgRegs[GPRIndex], + IsPPC64 ? &PPC::G8RCRegClass : &PPC::GPRCRegClass); + + SDValue Val = DAG.getCopyFromReg(Chain, dl, VReg, PtrVT); + //store to stack + SDValue Store = + DAG.getStore(Val.getValue(1), dl, Val, FIN, MachinePointerInfo()); + MemOps.push_back(Store); + // Increment the address for the next argument to store + SDValue PtrOff = DAG.getConstant(PtrVT.getSizeInBits() / 8, dl, PtrVT); + FIN = DAG.getNode(ISD::ADD, dl, PtrOff.getValueType(), FIN, PtrOff); + } + } + + if (!MemOps.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOps); return Chain; -} + } SDValue PPCTargetLowering::LowerCall_AIX( SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool isVarArg, @@ -7097,6 +7173,7 @@ // The LSA is 24 bytes (6x4) in PPC32 and 48 bytes (6x8) in PPC64. const unsigned LinkageSize = Subtarget.getFrameLowering()->getLinkageSize(); const bool IsPPC64 = Subtarget.isPPC64(); + const EVT PtrVT = getPointerTy(DAG.getDataLayout()); const unsigned PtrByteSize = IsPPC64 ? 8 : 4; CCInfo.AllocateStack(LinkageSize, PtrByteSize); CCInfo.AnalyzeCallOperands(Outs, CC_AIX); @@ -7108,7 +7185,8 @@ // conservatively assume that it is needed. As such, make sure we have at // least enough stack space for the caller to store the 8 GPRs. const unsigned MinParameterSaveAreaSize = 8 * PtrByteSize; - const unsigned NumBytes = LinkageSize + MinParameterSaveAreaSize; + const unsigned NumBytes = std::max(LinkageSize + MinParameterSaveAreaSize, + CCInfo.getNextStackOffset()); // Adjust the stack pointer for the new arguments... // These operations are automatically eliminated by the prolog/epilog pass. @@ -7116,19 +7194,32 @@ SDValue CallSeqStart = Chain; SmallVector, 8> RegsToPass; + SmallVector MemOpChains; + + // Set up a copy of the stack pointer for loading and storing any + // arguments that may not fit in the registers available for argument + // passing. + const SDValue StackPtr = IsPPC64 ? DAG.getRegister(PPC::X1, MVT::i64) + : DAG.getRegister(PPC::R1, MVT::i32); for (unsigned I = 0, E = ArgLocs.size(); I != E;) { CCValAssign &VA = ArgLocs[I++]; - if (VA.isMemLoc()) - report_fatal_error("Handling of placing parameters on the stack is " - "unimplemented!"); - if (!VA.isRegLoc()) - report_fatal_error( - "Unexpected non-register location for function call argument."); - SDValue Arg = OutVals[VA.getValNo()]; + if (!VA.isRegLoc() && !VA.isMemLoc()) + report_fatal_error("Unexpected location for function call argument."); + + if (VA.isMemLoc()) { + SDValue PtrOff = + DAG.getConstant(VA.getLocMemOffset(), dl, StackPtr.getValueType()); + PtrOff = DAG.getNode(ISD::ADD, dl, PtrVT, StackPtr, PtrOff); + MemOpChains.push_back( + DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo())); + + continue; + } + if (!VA.needsCustom()) { switch (VA.getLocInfo()) { default: @@ -7183,6 +7274,9 @@ } } + if (!MemOpChains.empty()) + Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains); + // For indirect calls, we need to save the TOC base to the stack for // restoration after the call. if (!isTailCall && !isPatchPoint && diff --git a/llvm/test/CodeGen/PowerPC/aix-xcoff-hidden.ll b/llvm/test/CodeGen/PowerPC/aix-xcoff-hidden.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-xcoff-hidden.ll @@ -0,0 +1,44 @@ +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s +; RUN: llc -verify-machineinstrs -mtriple powerpc64-ibm-aix-xcoff < %s | FileCheck %s + +@b = global i32 0, align 4 +@b_h = hidden global i32 0, align 4 + +define i32 @foo(i32* %ip) #0 { +entry: + %ip.addr = alloca i32*, align 4 + store i32* %ip, i32** %ip.addr, align 4 + %0 = load i32*, i32** %ip.addr, align 4 + %1 = load i32, i32* %0, align 4 + %inc = add nsw i32 %1, 1 + store i32 %inc, i32* %0, align 4 + ret i32 %1 +} + +define hidden i32 @foo_h(i32* %ip) #0 { +entry: + %ip.addr = alloca i32*, align 4 + store i32* %ip, i32** %ip.addr, align 4 + %0 = load i32*, i32** %ip.addr, align 4 + %1 = load i32, i32* %0, align 4 + %inc = add nsw i32 %1, 1 + store i32 %inc, i32* %0, align 4 + ret i32 %1 +} + +define i32 @main() #0 { +entry: + %call1= call i32 @bar_h(i32* @b_h) + ret i32 0 +} + +declare hidden i32 @bar_h(i32*) #1 + +; CHECK: .globl foo[DS] +; CHECK: .globl .foo +; CHECK: .globl foo_h[DS] , hidden +; CHECK: .globl .foo_h , hidden + +; CHECK: .globl b +; CHECK: .globl b_h , hidden +; CHECK: .extern .bar_h , hidden