diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h --- a/llvm/include/llvm/BinaryFormat/XCOFF.h +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -296,6 +296,24 @@ StringRef getRelocationTypeString(XCOFF::RelocationType Type); struct TracebackTable { + enum LanguageID : uint8_t { + C, + Fortran, + Pascal, + Ada, + PL1, + Basic, + LISP, + COBOL, + Modula2, + CPLUSPLUS, + RPG, + PL8, + PLIX, + Assembly, + Java, + ObjectiveC + }; // Byte 1 static constexpr uint32_t VersionMask = 0xFF00'0000; static constexpr uint8_t VersionShift = 24; diff --git a/llvm/include/llvm/CodeGen/CommandFlags.h b/llvm/include/llvm/CodeGen/CommandFlags.h --- a/llvm/include/llvm/CodeGen/CommandFlags.h +++ b/llvm/include/llvm/CodeGen/CommandFlags.h @@ -99,6 +99,8 @@ bool getIgnoreXCOFFVisibility(); +bool getXCOFFTracebackTable(); + std::string getBBSections(); std::string getStackProtectorGuard(); diff --git a/llvm/include/llvm/Target/TargetMachine.h b/llvm/include/llvm/Target/TargetMachine.h --- a/llvm/include/llvm/Target/TargetMachine.h +++ b/llvm/include/llvm/Target/TargetMachine.h @@ -272,6 +272,11 @@ return Options.IgnoreXCOFFVisibility; } + /// Return true if should emit traceback table for asm in AIX OS or xcoff + /// object file + /// corresponding to -xcoff-traceback-table. + bool getXCOFFTracebackTable() const { return Options.XCOFFTracebackTable; } + /// If basic blocks should be emitted into their own section, /// corresponding to -fbasic-block-sections. llvm::BasicBlockSection getBBSectionsType() const { diff --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h --- a/llvm/include/llvm/Target/TargetOptions.h +++ b/llvm/include/llvm/Target/TargetOptions.h @@ -130,10 +130,10 @@ EnableFastISel(false), EnableGlobalISel(false), UseInitArray(false), DisableIntegratedAS(false), RelaxELFRelocations(false), FunctionSections(false), DataSections(false), - IgnoreXCOFFVisibility(false), UniqueSectionNames(true), - UniqueBasicBlockSectionNames(false), TrapUnreachable(false), - NoTrapAfterNoreturn(false), TLSSize(0), EmulatedTLS(false), - ExplicitEmulatedTLS(false), EnableIPRA(false), + IgnoreXCOFFVisibility(false), XCOFFTracebackTable(false), + UniqueSectionNames(true), UniqueBasicBlockSectionNames(false), + TrapUnreachable(false), NoTrapAfterNoreturn(false), TLSSize(0), + EmulatedTLS(false), ExplicitEmulatedTLS(false), EnableIPRA(false), EmitStackSizeSection(false), EnableMachineOutliner(false), EnableMachineFunctionSplitter(false), SupportsDefaultOutlining(false), EmitAddrsig(false), EmitCallSiteInfo(false), @@ -247,6 +247,9 @@ /// Do not emit visibility attribute for xcoff. unsigned IgnoreXCOFFVisibility : 1; + /// Emit traceback table for asm in AIX OS or xcoff object file. + unsigned XCOFFTracebackTable : 1; + unsigned UniqueSectionNames : 1; /// Use unique names for basic block sections. diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp --- a/llvm/lib/CodeGen/CommandFlags.cpp +++ b/llvm/lib/CodeGen/CommandFlags.cpp @@ -76,6 +76,7 @@ CGOPT_EXP(bool, DataSections) CGOPT_EXP(bool, FunctionSections) CGOPT(bool, IgnoreXCOFFVisibility) +CGOPT(bool, XCOFFTracebackTable) CGOPT(std::string, BBSections) CGOPT(std::string, StackProtectorGuard) CGOPT(unsigned, StackProtectorGuardOffset) @@ -350,6 +351,13 @@ cl::init(false)); CGBINDOPT(IgnoreXCOFFVisibility); + static cl::opt XCOFFTracebackTable( + "xcoff-traceback-table", + cl::desc( + "Emit the traceback table for asm in AIX OS or in XCOFF object file"), + cl::init(false)); + CGBINDOPT(XCOFFTracebackTable); + static cl::opt BBSections( "basic-block-sections", cl::desc("Emit basic blocks into separate sections"), @@ -533,6 +541,7 @@ getExplicitDataSections().getValueOr(TheTriple.hasDefaultDataSections()); Options.FunctionSections = getFunctionSections(); Options.IgnoreXCOFFVisibility = getIgnoreXCOFFVisibility(); + Options.XCOFFTracebackTable = getXCOFFTracebackTable(); Options.BBSections = getBBSectionsMode(Options); Options.UniqueSectionNames = getUniqueSectionNames(); Options.UniqueBasicBlockSectionNames = getUniqueBasicBlockSectionNames(); 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 @@ -76,6 +76,7 @@ #include using namespace llvm; +using namespace llvm::XCOFF; #define DEBUG_TYPE "asmprinter" @@ -188,6 +189,8 @@ void emitFunctionEntryLabel() override; + void emitFunctionBodyEnd() override; + void emitEndOfAsmFile(Module &) override; void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const override; @@ -1735,6 +1738,258 @@ return AsmPrinter::SetupMachineFunction(MF); } +const char *SourceLanguageIdentifier[] = { + "C", "FORTRAN", "Pascal", "ADA", "PL/I", + "BASIC", "LISP", "COBOL", "Modulas2", "C++", + "RPG", "PL8", "Assembler", "Java", "Objective C"}; + +void PPCAIXAsmPrinter::emitFunctionBodyEnd() { + + if (!TM.getXCOFFTracebackTable()) + return; + + // Create a symbol for the end of function. + MCSymbol *FuncEnd = createTempSymbol(MF->getName()); + OutStreamer->emitLabel(FuncEnd); + + uint8_t Version = 0; + uint8_t LanguageIdentifier = TracebackTable::CPLUSPLUS; // C++ + uint32_t FirstHalfOfMandatoryField = 0; + + OutStreamer->AddComment("Traceback table begin"); + // Begin with a fullword of zero. + OutStreamer->emitIntValueInHexWithPadding(0, 4 /*size*/); + + std::string CommentString; + raw_string_ostream CommentOS(CommentString); + +#define OUTPUTCOMMENTVALUE(X, S) \ + OutStreamer->AddComment(CommentOS.str()); \ + CommentString.clear(); \ + OutStreamer->emitIntValueInHexWithPadding(X, S) + +#define OUTPUTCOMMENT \ + OutStreamer->AddComment(CommentOS.str()); \ + CommentString.clear() + + CommentOS << "Version = " << (unsigned int)Version; + OUTPUTCOMMENTVALUE(Version, 1); + + assert(LanguageIdentifier < + sizeof(SourceLanguageIdentifier) / sizeof(char *) && + "Unknown Language ID."); + CommentOS << "Language = " << SourceLanguageIdentifier[LanguageIdentifier]; + OUTPUTCOMMENTVALUE(LanguageIdentifier, 1); + + const PPCFunctionInfo *FI = MF->getInfo(); + const MachineRegisterInfo &MRI = MF->getRegInfo(); + + // Emit the 3th byte of the mandatory field. + if (MF->getFunction().hasExternalLinkage()) + FirstHalfOfMandatoryField |= TracebackTable::IsGlobaLinkageMask; + + // We always set traceback offset bit to true. + FirstHalfOfMandatoryField |= TracebackTable::HasTraceBackTableOffsetMask; + + if (MF->getFunction().hasInternalLinkage()) + FirstHalfOfMandatoryField |= TracebackTable::IsInternalProcedureMask; + + if (!FI->usesTOCBasePtr()) + FirstHalfOfMandatoryField |= TracebackTable::IsTOClessMask; + + // Check the function uses floating-point processor instructions or not + bool FPFound = false; + for (MachineFunction::iterator BI = MF->begin(), BE = MF->end(); + BI != BE && !FPFound; ++BI) + for (MachineBasicBlock::iterator MBBI = BI->begin(); + MBBI != BI->end() && !FPFound; MBBI++) { + for (unsigned I = 0, E = MBBI->getNumOperands(); I != E; ++I) { + MachineOperand &MO = MBBI->getOperand(I); + if (!MO.isReg()) + continue; + + if (MO.getReg() >= PPC::F0 && MO.getReg() <= PPC::F31) { + FirstHalfOfMandatoryField |= + TracebackTable::IsFloatingPointPresentMask; + FPFound = true; + break; + } + } + } + +#define PRINTBOOL(Prefix, V, Field) \ + CommentOS << Prefix << (V & (TracebackTable::Field##Mask) ? "+" : "-") \ + << #Field + +#define PRINTGET(Prefix, V, Field, Name) \ + CommentOS << Prefix << #Name << " = " \ + << (unsigned)(V & (TracebackTable::Field##Mask) >> \ + (TracebackTable::Field##Shift)) + + PRINTBOOL(" ", FirstHalfOfMandatoryField, IsGlobaLinkage); + PRINTBOOL(",", FirstHalfOfMandatoryField, IsOutOfLineEpilogOrPrologue); + OUTPUTCOMMENT; + + PRINTBOOL(" ", FirstHalfOfMandatoryField, HasTraceBackTableOffset); + PRINTBOOL(",", FirstHalfOfMandatoryField, IsInternalProcedure); + OUTPUTCOMMENT; + + PRINTBOOL(" ", FirstHalfOfMandatoryField, HasControlledStorage); + PRINTBOOL(",", FirstHalfOfMandatoryField, IsTOCless); + OUTPUTCOMMENT; + + PRINTBOOL(" ", FirstHalfOfMandatoryField, IsFloatingPointPresent); + OUTPUTCOMMENT; + PRINTBOOL(" ", FirstHalfOfMandatoryField, + IsFloatingPointOperationLogOrAbortEnabled); + OUTPUTCOMMENT; + + OutStreamer->emitIntValueInHexWithPadding( + (FirstHalfOfMandatoryField & 0x0000ff00) >> 8, 1); + + // Set the 4th byte of the mandatory field. + FirstHalfOfMandatoryField |= TracebackTable::IsFunctionNamePresentMask; + + if (MRI.isPhysRegUsed(PPC::R31)) + FirstHalfOfMandatoryField |= TracebackTable::IsAllocaUsedMask; + + const SmallVectorImpl &MustSaveCRs = FI->getMustSaveCRs(); + if (!MustSaveCRs.empty()) + FirstHalfOfMandatoryField |= TracebackTable::IsCRSavedMask; + + if (FI->mustSaveLR()) + FirstHalfOfMandatoryField |= TracebackTable::IsLRSavedMask; + + PRINTBOOL(" ", FirstHalfOfMandatoryField, IsInterruptHandler); + PRINTBOOL(",", FirstHalfOfMandatoryField, IsFunctionNamePresent); + PRINTBOOL(",", FirstHalfOfMandatoryField, IsAllocaUsed); + OUTPUTCOMMENT; + PRINTGET(" ", FirstHalfOfMandatoryField, OnConditionDirective, + OnConditionDirective); + PRINTBOOL(",", FirstHalfOfMandatoryField, IsCRSaved); + PRINTBOOL(",", FirstHalfOfMandatoryField, IsLRSaved); + OUTPUTCOMMENT; + OutStreamer->emitIntValueInHexWithPadding((FirstHalfOfMandatoryField & 0xff), + 1); + + // Set the 5th byte of mandatory field. + uint32_t SecondHalfOfMandatoryField = 0; + + // Always store back chain. + SecondHalfOfMandatoryField |= TracebackTable::IsBackChainStoredMask; + + uint32_t FPRSaved = 0; + for (unsigned Reg = PPC::F14; Reg <= PPC::F31; Reg++) { + if (MRI.isPhysRegModified(Reg)) { + FPRSaved = PPC::F31 - Reg + 1; + break; + } + } + + PRINTBOOL(" ", SecondHalfOfMandatoryField, IsBackChainStored); + PRINTBOOL(",", SecondHalfOfMandatoryField, IsFixup); + PRINTGET(",", SecondHalfOfMandatoryField, FPRSaved, NumOfFPRsSaved); + OUTPUTCOMMENT; + OutStreamer->emitIntValueInHexWithPadding( + (SecondHalfOfMandatoryField & 0xff000000) >> 24, 1); + + // Set the 6th byte of mandatory field. + SecondHalfOfMandatoryField |= (FPRSaved << TracebackTable::FPRSavedShift) & + TracebackTable::FPRSavedMask; + + uint32_t GPRSaved = 0; + + // X13 is reserved under 64-bit environment. + unsigned GPRBegin = Subtarget->isPPC64() ? PPC::X14 : PPC::R13; + unsigned GPREnd = Subtarget->isPPC64() ? PPC::X31 : PPC::R31; + + for (unsigned Reg = GPRBegin; Reg <= GPREnd; Reg++) { + if (MRI.isPhysRegModified(Reg)) { + GPRSaved = GPREnd - Reg + 1; + break; + } + } + + SecondHalfOfMandatoryField |= (GPRSaved << TracebackTable::GPRSavedShift) & + TracebackTable::GPRSavedMask; + + PRINTBOOL(" ", SecondHalfOfMandatoryField, HasExtensionTable); + PRINTBOOL(",", SecondHalfOfMandatoryField, HasVectorInfo); + PRINTGET(",", SecondHalfOfMandatoryField, GPRSaved, NumOfGPRsSaved); + OUTPUTCOMMENT; + OutStreamer->emitIntValueInHexWithPadding( + (SecondHalfOfMandatoryField & 0x00ff0000) >> 16, 1); + + // Set the 7th byte of mandatory field. + uint32_t NumberOfFixedPara = FI->getFixedParameter(); + SecondHalfOfMandatoryField |= + (NumberOfFixedPara << TracebackTable::NumberOfFixedParmsShift) & + TracebackTable::NumberOfFixedParmsMask; + PRINTGET("#", SecondHalfOfMandatoryField, NumberOfFixedParms, + NumberOfFixedParms); + OUTPUTCOMMENT; + OutStreamer->emitIntValueInHexWithPadding( + (SecondHalfOfMandatoryField & 0x0000ff00) >> 8, 1); + + // Set the 8th byte of mandatory field. + + // Always set parameter on stack. + SecondHalfOfMandatoryField |= TracebackTable::HasParmsOnStackMask; + + uint32_t NumberOfFPPara = FI->getFloatPointParameter(); + SecondHalfOfMandatoryField |= + (NumberOfFPPara << TracebackTable::NumberOfFloatingPointParmsShift) & + TracebackTable::NumberOfFloatingPointParmsMask; + + PRINTGET("#", SecondHalfOfMandatoryField, NumberOfFloatingPointParms, + NumberOfFPParms); + PRINTBOOL(",", SecondHalfOfMandatoryField, HasParmsOnStack); + OUTPUTCOMMENT; + OutStreamer->emitIntValueInHexWithPadding(SecondHalfOfMandatoryField & 0xff, + 1); + + // Generate the optional fields of traceback table. + + // Parameter type. + if (NumberOfFixedPara || NumberOfFPPara) { + uint32_t ParaType = FI->getParameterType(); + OutStreamer->AddComment("Parameter type"); + OutStreamer->emitIntValueInHexWithPadding(ParaType, sizeof(ParaType)); + } + + // Traceback table offset. + OutStreamer->AddComment("Function size"); + if (FirstHalfOfMandatoryField & TracebackTable::HasTraceBackTableOffsetMask) { + MCSymbol *FuncSectSym = getObjFileLowering().getFunctionEntryPointSymbol( + &(MF->getFunction()), TM); + OutStreamer->emitAbsoluteSymbolDiff(FuncEnd, FuncSectSym, 4); + } + + if (FirstHalfOfMandatoryField & TracebackTable::IsInterruptHandlerMask) + report_fatal_error("Hand_Mask not implement yes"); + + // Since we unset the Int_Handler. + if (FirstHalfOfMandatoryField & TracebackTable::HasControlledStorageMask) + report_fatal_error("Ctl_Info not implement yes"); + + if (FirstHalfOfMandatoryField & TracebackTable::IsFunctionNamePresentMask) { + StringRef Name = MF->getName(); + uint16_t NameLength = Name.size(); + CommentOS << "Function name len = " << (unsigned int)NameLength; + OUTPUTCOMMENTVALUE(NameLength, 2); + OutStreamer->AddComment("Function Name"); + OutStreamer->emitBytes(Name); + } + + if (FirstHalfOfMandatoryField & TracebackTable::IsAllocaUsedMask) { + uint8_t Alloc_Reg = + Subtarget->isPPC64() ? PPC::X31 - PPC::X0 : PPC::R31 - PPC::R0; + OutStreamer->AddComment("AllocaUsed"); + OUTPUTCOMMENT; + OutStreamer->emitIntValueInHex(Alloc_Reg, sizeof(Alloc_Reg)); + } +} + void PPCAIXAsmPrinter::ValidateGV(const GlobalVariable *GV) { // Early error checking limiting what is supported. if (GV->isThreadLocal()) 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 @@ -3572,6 +3572,11 @@ PPC::F6, PPC::F7, PPC::F8, PPC::F9, PPC::F10, PPC::F11, PPC::F12, PPC::F13}; +static const MCPhysReg GPR_32[] = { // 32-bit registers. + PPC::R3, PPC::R4, PPC::R5, PPC::R6, PPC::R7, PPC::R8, PPC::R9, PPC::R10}; +static const MCPhysReg GPR_64[] = { // 64-bit registers. + PPC::X3, PPC::X4, PPC::X5, PPC::X6, PPC::X7, PPC::X8, PPC::X9, PPC::X10}; + /// CalculateStackSlotSize - Calculates the size reserved for this argument on /// the stack. static unsigned CalculateStackSlotSize(EVT ArgVT, ISD::ArgFlagsTy Flags, @@ -7016,13 +7021,6 @@ if (ValVT.isVector() || LocVT.isVector()) report_fatal_error("Vector arguments are unimplemented on AIX."); - static const MCPhysReg GPR_32[] = {// 32-bit registers. - PPC::R3, PPC::R4, PPC::R5, PPC::R6, - PPC::R7, PPC::R8, PPC::R9, PPC::R10}; - static const MCPhysReg GPR_64[] = {// 64-bit registers. - PPC::X3, PPC::X4, PPC::X5, PPC::X6, - PPC::X7, PPC::X8, PPC::X9, PPC::X10}; - if (ArgFlags.isByVal()) { if (ArgFlags.getNonZeroByValAlign() > PtrAlign) report_fatal_error("Pass-by-value arguments with alignment greater than " @@ -7240,6 +7238,7 @@ SmallVector ArgLocs; MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); + PPCFunctionInfo *FuncInfo = MF.getInfo(); CCState CCInfo(CallConv, isVarArg, MF, ArgLocs, *DAG.getContext()); const EVT PtrVT = getPointerTy(MF.getDataLayout()); @@ -7264,6 +7263,34 @@ if (VA.isMemLoc() && VA.needsCustom()) continue; + if (VA.isRegLoc()) { + const MCPhysReg ArgReg = VA.getLocReg(); + bool FoundReg = false; + for (auto Reg : IsPPC64 ? GPR_64 : GPR_32) { + if (Reg == ArgReg) { + FuncInfo->incFixedParameter(); + FoundReg = true; + break; + } + } + + if (!FoundReg) { + FoundReg = false; + for (auto Reg : FPR) { + if (Reg == ArgReg) { + FuncInfo->incFloatPointParameter(); + FuncInfo->setParameterType(VA.getValVT().SimpleTy == MVT::f32 + ? PPCFunctionInfo::ShortFloatPoint + : PPCFunctionInfo::LongFloatPoint, + VA.getValNo()); + FoundReg = true; + break; + } + } + } + assert(FoundReg && "Should found a register."); + } + if (Flags.isByVal() && VA.isMemLoc()) { const unsigned Size = alignTo(Flags.getByValSize() ? Flags.getByValSize() : PtrByteSize, @@ -7327,6 +7354,7 @@ const CCValAssign RL = ArgLocs[I++]; HandleRegLoc(RL.getLocReg(), Offset); + FuncInfo->incFixedParameter(); } if (Offset != StackSize) { @@ -7389,7 +7417,6 @@ // aligned stack. CallerReservedArea = EnsureStackAlignment(Subtarget.getFrameLowering(), CallerReservedArea); - PPCFunctionInfo *FuncInfo = MF.getInfo(); FuncInfo->setMinReservedArea(CallerReservedArea); if (isVarArg) { diff --git a/llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.h b/llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.h --- a/llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.h +++ b/llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.h @@ -22,6 +22,10 @@ /// PPCFunctionInfo - This class is derived from MachineFunction private /// PowerPC target-specific information for each MachineFunction. class PPCFunctionInfo : public MachineFunctionInfo { +public: + enum ParaType { FixedType = 0, ShortFloatPoint = 2, LongFloatPoint = 3 }; + +private: virtual void anchor(); /// FramePointerSaveIndex - Frame index of where the old frame pointer is @@ -107,6 +111,19 @@ /// register for parameter passing. unsigned VarArgsNumFPR = 0; + /// NumFixedPara - Number of Fixed parameter. + unsigned NumFixedPara = 0; + + /// NumFloatPara - Number of float point parameter. + unsigned NumFloatPointPara = 0; + + /// ParaType - Encode type for each parameter pass. + /// in ord of parameter pass. + /// '0'b => fixed parameter. + /// '10'b => float point short parameter. + /// '11'b => float point long parameter. + unsigned ParameterType = 0; + /// CRSpillFrameIndex - FrameIndex for CR spill slot for 32-bit SVR4. int CRSpillFrameIndex = 0; @@ -190,6 +207,15 @@ unsigned getVarArgsNumGPR() const { return VarArgsNumGPR; } void setVarArgsNumGPR(unsigned Num) { VarArgsNumGPR = Num; } + unsigned getFixedParameter() const { return NumFixedPara; } + void incFixedParameter() { NumFixedPara++; } + + unsigned getFloatPointParameter() const { return NumFloatPointPara; } + void incFloatPointParameter() { NumFloatPointPara++; } + + unsigned getParameterType() const { return ParameterType; } + void setParameterType(ParaType Type, unsigned RegNo); + unsigned getVarArgsNumFPR() const { return VarArgsNumFPR; } void setVarArgsNumFPR(unsigned Num) { VarArgsNumFPR = Num; } diff --git a/llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.cpp b/llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.cpp --- a/llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCMachineFunctionInfo.cpp @@ -63,3 +63,25 @@ return LiveIn.second.isZExt(); return false; } + +void PPCFunctionInfo::setParameterType(ParaType Type, unsigned RegNo) { + unsigned CopyParaType = ParameterType; + unsigned Bits = 0; + for (unsigned i = 0; i < RegNo; i++) { + if (CopyParaType & 0x80000000) { + // '10'b => float point short parameter. + // '11'b => float point long parameter. + CopyParaType <<= 2; + Bits += 2; + } else { + // '0'b => fixed parameter. + CopyParaType <<= 1; + Bits++; + } + } + + if (Type == FixedType) + ParameterType |= Type << (31 - Bits); + else + ParameterType |= Type << (30 - Bits); +} diff --git a/llvm/test/CodeGen/PowerPC/aix-emit-tracebacktable.ll b/llvm/test/CodeGen/PowerPC/aix-emit-tracebacktable.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/aix-emit-tracebacktable.ll @@ -0,0 +1,205 @@ +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \ +; RUN: -mattr=-altivec -xcoff-traceback-table < %s | \ +; RUN: FileCheck --check-prefixes=CHECK-ASM,COMMON %s + +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -function-sections \ +; RUN: -mcpu=pwr4 -mattr=-altivec -xcoff-traceback-table < %s | \ +; RUN: FileCheck --check-prefixes=CHECK-FUNC,COMMON %s + +; RUN: llc -verify-machineinstrs -mtriple powerpc-ibm-aix-xcoff -mcpu=pwr4 \ +; RUN: -mattr=-altivec -filetype=obj -xcoff-traceback-table -o %t.o < %s +; RUN llvm-objdump -D --xcoff-traceback-table %t.o | FileCheck --check-prefix=CHECKDIS %s + +%struct.S = type { i32, i32 } +%struct.D = type { float, double } +%struct.SD = type { %struct.S*, %struct.D } + +@__const.main.s = private unnamed_addr constant %struct.S { i32 10, i32 20 }, align 4 +@__const.main.d = private unnamed_addr constant %struct.D { float 1.000000e+01, double 2.000000e+01 }, align 8 + +define double @_Z10add_structifd1SP2SD1Di(i32 %value, float %fvalue, double %dvalue, %struct.S* byval(%struct.S) align 4 %s, %struct.SD* %dp, %struct.D* byval(%struct.D) align 4 %0, i32 %v2) #0 { +entry: + %d = alloca %struct.D, align 8 + %value.addr = alloca i32, align 4 + %fvalue.addr = alloca float, align 4 + %dvalue.addr = alloca double, align 8 + %dp.addr = alloca %struct.SD*, align 4 + %v2.addr = alloca i32, align 4 + %1 = bitcast %struct.D* %d to i8* + %2 = bitcast %struct.D* %0 to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %1, i8* align 4 %2, i32 16, i1 false) + store i32 %value, i32* %value.addr, align 4 + store float %fvalue, float* %fvalue.addr, align 4 + store double %dvalue, double* %dvalue.addr, align 8 + store %struct.SD* %dp, %struct.SD** %dp.addr, align 4 + store i32 %v2, i32* %v2.addr, align 4 + %3 = load double, double* %dvalue.addr, align 8 + %4 = load float, float* %fvalue.addr, align 4 + %conv = fpext float %4 to double + %add = fadd double %3, %conv + %5 = load i32, i32* %value.addr, align 4 + %conv1 = sitofp i32 %5 to double + %add2 = fadd double %add, %conv1 + %i1 = getelementptr inbounds %struct.S, %struct.S* %s, i32 0, i32 0 + %6 = load i32, i32* %i1, align 4 + %conv3 = sitofp i32 %6 to double + %add4 = fadd double %add2, %conv3 + %7 = load %struct.SD*, %struct.SD** %dp.addr, align 4 + %d5 = getelementptr inbounds %struct.SD, %struct.SD* %7, i32 0, i32 1 + %d1 = getelementptr inbounds %struct.D, %struct.D* %d5, i32 0, i32 1 + %8 = load double, double* %d1, align 8 + %add6 = fadd double %add4, %8 + %f1 = getelementptr inbounds %struct.D, %struct.D* %d, i32 0, i32 0 + %9 = load float, float* %f1, align 8 + %conv7 = fpext float %9 to double + %add8 = fadd double %add6, %conv7 + %10 = load i32, i32* %v2.addr, align 4 + %conv9 = sitofp i32 %10 to double + %add10 = fadd double %add8, %conv9 + ret double %add10 +} + +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i32, i1 immarg) #1 + +define i32 @main() { +entry: + %retval = alloca i32, align 4 + %s = alloca %struct.S, align 4 + %d = alloca %struct.D, align 8 + %sd = alloca %struct.SD, align 8 + %agg.tmp = alloca %struct.S, align 4 + %agg.tmp4 = alloca %struct.D, align 8 + store i32 0, i32* %retval, align 4 + %0 = bitcast %struct.S* %s to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 bitcast (%struct.S* @__const.main.s to i8*), i32 8, i1 false) + %1 = bitcast %struct.D* %d to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %1, i8* align 8 bitcast (%struct.D* @__const.main.d to i8*), i32 16, i1 false) + %sp = getelementptr inbounds %struct.SD, %struct.SD* %sd, i32 0, i32 0 + store %struct.S* %s, %struct.S** %sp, align 8 + %d1 = getelementptr inbounds %struct.SD, %struct.SD* %sd, i32 0, i32 1 + %f1 = getelementptr inbounds %struct.D, %struct.D* %d1, i32 0, i32 0 + store float 1.000000e+02, float* %f1, align 8 + %d2 = getelementptr inbounds %struct.SD, %struct.SD* %sd, i32 0, i32 1 + %d13 = getelementptr inbounds %struct.D, %struct.D* %d2, i32 0, i32 1 + store double 2.000000e+02, double* %d13, align 8 + %2 = bitcast %struct.S* %agg.tmp to i8* + %3 = bitcast %struct.S* %s to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %2, i8* align 4 %3, i32 8, i1 false) + %4 = bitcast %struct.D* %agg.tmp4 to i8* + %5 = bitcast %struct.D* %d to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 8 %4, i8* align 8 %5, i32 16, i1 false) + %call = call double @_Z10add_structifd1SP2SD1Di(i32 1, float 2.000000e+00, double 3.000000e+00, %struct.S* byval(%struct.S) align 4 %agg.tmp, %struct.SD* %sd, %struct.D* byval(%struct.D) align 4 %agg.tmp4, i32 7) + %add = fadd double %call, 1.000000e+00 + %conv = fptosi double %add to i32 + ret i32 %conv +} + +; CHECK-ASM-LABEL: ._Z10add_structifd1SP2SD1Di:{{[[:space:]] *}}# %bb.0: +; CHECK-FUNC-LABEL: csect ._Z10add_structifd1SP2SD1Di[PR],2{{[[:space:]] *}}# %bb.0: +; COMMON-NEXT: lwz 4, L..C0(2) +; COMMON-NEXT: stfs 1, -24(1) +; COMMON-NEXT: lfs 0, 0(4) +; COMMON-NEXT: lwz 4, 56(1) +; COMMON: fsub 0, 2, 0 +; COMMON-NEXT: stw 9, -36(1) +; COMMON-NEXT: fadd 1, 1, 0 +; COMMON-NEXT: blr +; COMMON-NEXT: L.._Z10add_structifd1SP2SD1Di0: +; COMMON-NEXT: .vbyte 4, 0x00000000 # Traceback table begin +; COMMON-NEXT: .byte 0x00 # Version = 0 +; COMMON-NEXT: .byte 0x09 # Language = C++ +; COMMON-NEXT: .byte 0xa2 # +IsGlobaLinkage,-IsOutOfLineEpilogOrPrologue +; COMMON-NEXT: # +HasTraceBackTableOffset,-IsInternalProcedure +; COMMON-NEXT: # -HasControlledStorage,-IsTOCless +; COMMON-NEXT: # +IsFloatingPointPresent +; COMMON-NEXT: # -IsFloatingPointOperationLogOrAbortEnabled +; COMMON-NEXT: .byte 0x40 # -IsInterruptHandler,+IsFunctionNamePresent,-IsAllocaUsed +; COMMON-NEXT: # OnConditionDirective = 0,-IsCRSaved,-IsLRSaved +; COMMON-NEXT: .byte 0x80 # +IsBackChainStored,-IsFixup,NumOfFPRsSaved = 0 +; COMMON-NEXT: .byte 0x00 # -HasExtensionTable,-HasVectorInfo,NumOfGPRsSaved = 0 +; COMMON-NEXT: .byte 0x05 # #NumberOfFixedParms = 0 +; COMMON-NEXT: .byte 0x05 # #NumberOfFPParms = 5,+HasParmsOnStack +; COMMON-NEXT: .vbyte 4, 0x58000000 # Parameter type +; CHECK-ASM-NEXT: .vbyte 4, L.._Z10add_structifd1SP2SD1Di0-._Z10add_structifd1SP2SD1Di # Function size +; CHECK-FUNC-NEXT: .vbyte 4, L.._Z10add_structifd1SP2SD1Di0-._Z10add_structifd1SP2SD1Di[PR] # Function size +; COMMON-NEXT: .vbyte 2, 0x001a # Function name len = 26 +; COMMON-NEXT: .byte '_,'Z,'1,'0,'a,'d,'d,'_,'s,'t,'r,'u,'c,'t,'i,'f,'d,'1,'S,'P,'2,'S,'D,'1,'D,'i # Function Name +; COMMON-NEXT: # -- End function + + +; CHECK-ASM-LABEL: .main:{{[[:space:]] *}}# %bb.0: +; CHECK-FUNC-LABEL: .csect .main[PR],2{{[[:space:]] *}}# %bb.0 +; COMMON-NEXT: mflr 0 +; COMMON-NEXT: stw 0, 8(1) +; COMMON-NEXT: stwu 1, -160(1) +; COMMON-NEXT: lwz 5, L..C1(2) +; COMMON-NEXT: addi 4, 1, 144 +; COMMON: addi 1, 1, 160 +; COMMON-NEXT: lwz 0, 8(1) +; COMMON-NEXT: mtlr 0 +; COMMON-NEXT: blr +; COMMON-NEXT: L..main0: +; COMMON-NEXT: .vbyte 4, 0x00000000 # Traceback table begin +; COMMON-NEXT: .byte 0x00 # Version = 0 +; COMMON-NEXT: .byte 0x09 # Language = C++ +; COMMON-NEXT: .byte 0xa2 # +IsGlobaLinkage,-IsOutOfLineEpilogOrPrologue +; COMMON-NEXT: # +HasTraceBackTableOffset,-IsInternalProcedure +; COMMON-NEXT: # -HasControlledStorage,-IsTOCless +; COMMON-NEXT: # +IsFloatingPointPresent +; COMMON-NEXT: # -IsFloatingPointOperationLogOrAbortEnabled +; COMMON-NEXT: .byte 0x41 # -IsInterruptHandler,+IsFunctionNamePresent,-IsAllocaUsed +; COMMON-NEXT: # OnConditionDirective = 1,-IsCRSaved,+IsLRSaved +; COMMON-NEXT: .byte 0x80 # +IsBackChainStored,-IsFixup,NumOfFPRsSaved = 0 +; COMMON-NEXT: .byte 0x00 # -HasExtensionTable,-HasVectorInfo,NumOfGPRsSaved = 0 +; COMMON-NEXT: .byte 0x00 # #NumberOfFixedParms = 0 +; COMMON-NEXT: .byte 0x01 # #NumberOfFPParms = 1,+HasParmsOnStack +; CHECK-ASM-NEXT: .vbyte 4, L..main0-.main # Function size +; CHECK-FUNC-NEXT: .vbyte 4, L..main0-.main[PR] # Function size +; COMMON-NEXT: .vbyte 2, 0x0004 # Function name len = 4 +; COMMON-NEXT: .byte 'm,'a,'i,'n # Function Name +; COMMON-NEXT: # -- End function + +; CHECKDIS: ac: 00 00 00 00 # Traceback table begin +; CHECKDIS-NEXT: b0: 00 # Version = 0 +; CHECKDIS-NEXT: b1: 09 # Language = C++ +; CHECKDIS-NEXT: b2: a2 # +isGlobalLinkage, -isOutOfLineEpilogOrPrologue +; CHECKDIS-NEXT: +hasTraceBackTableOffset, -isInternalProcedure +; CHECKDIS-NEXT: -hasControlledStorage, -isTOCless +; CHECKDIS-NEXT: +isFloatingPointPresent +; CHECKDIS-NEXT: -isFloatingPointOperationLogOrAbortEnabled +; CHECKDIS-NEXT: b3: 40 # -isInterruptHandler, +isFuncNamePresent, -isAllocaUsed +; CHECKDIS-NEXT: OnConditionDirective = 0, -isCRSaved, -isLRSaved +; CHECKDIS-NEXT: b4: 80 # +isBackChainStored, -isFixup, NumOfFPRsSaved = 0 +; CHECKDIS-NEXT: b5: 00 # -hasExtensionTable, -hasVectorInfo, NumOfGPRsSaved = 0 +; CHECKDIS-NEXT: b6: 05 # NumberOfFixedParms = 5 +; CHECKDIS-NEXT: b7: 05 # NumberOfFPParms = 2, +hasParmsOnStack +; CHECKDIS-NEXT: b8: 58 00 00 00 # ParmsType = i, f, d, i, i, i, i +; CHECKDIS-NEXT: bc: 00 00 00 ac # TraceBackTableOffset = 172 +; CHECKDIS-NEXT: c0: 00 1a # FunctionNameLen = 26 +; CHECKDIS-NEXT: c2: 5f 5a 31 30 # FunctionName = _Z10add_structifd1SP2SD1Di +; CHECKDIS-NEXT: c6: 61 64 64 5f +; CHECKDIS-NEXT: ca: 73 74 72 75 +; CHECKDIS-NEXT: ce: 63 74 69 66 +; CHECKDIS-NEXT: d2: 64 31 53 50 +; CHECKDIS-NEXT: d6: 32 53 44 31 +; CHECKDIS-NEXT: da: 44 69 +; CHECKDIS-NEXT: ... + +; CHECKDIS-NEXT: 1dc: 00 00 00 00 # Traceback table begin +; CHECKDIS-NEXT: 1e0: 00 # Version = 0 +; CHECKDIS-NEXT: 1e1: 09 # Language = C++ +; CHECKDIS-NEXT: 1e2: a2 # +isGlobalLinkage, -isOutOfLineEpilogOrPrologue +; CHECKDIS-NEXT: +hasTraceBackTableOffset, -isInternalProcedure +; CHECKDIS-NEXT: -hasControlledStorage, -isTOCless +; CHECKDIS-NEXT: +isFloatingPointPresent +; CHECKDIS-NEXT: -isFloatingPointOperationLogOrAbortEnabled +; CHECKDIS-NEXT: 1e3: 41 # -isInterruptHandler, +isFuncNamePresent, -isAllocaUsed +; CHECKDIS-NEXT: OnConditionDirective = 0, -isCRSaved, +isLRSaved +; CHECKDIS-NEXT: 1e4: 80 # +isBackChainStored, -isFixup, NumOfFPRsSaved = 0 +; CHECKDIS-NEXT: 1e5: 00 # -hasExtensionTable, -hasVectorInfo, NumOfGPRsSaved = 0 +; CHECKDIS-NEXT: 1e6: 00 # NumberOfFixedParms = 0 +; CHECKDIS-NEXT: 1e7: 01 # NumberOfFPParms = 0, +hasParmsOnStack +; CHECKDIS-NEXT: 1e8: 00 00 00 fc # TraceBackTableOffset = 252 +; CHECKDIS-NEXT: 1ec: 00 04 # FunctionNameLen = 4 +; CHECKDIS-NEXT: 1ee: 6d 61 69 6e # FunctionName = main +; CHECKDIS-NEXT: ...