Index: llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp =================================================================== --- llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -420,6 +420,7 @@ bool parseAddressRegister(Register &Reg); bool ParseDirectiveInsn(SMLoc L); + bool ParseGNUAttribute(SMLoc L); OperandMatchResultTy parseAddress(OperandVector &Operands, MemoryKind MemKind, @@ -1210,6 +1211,8 @@ if (IDVal == ".insn") return ParseDirectiveInsn(DirectiveID.getLoc()); + if (IDVal.startswith(".gnu_attribute")) + return ParseGNUAttribute(DirectiveID.getLoc()); return true; } @@ -1322,6 +1325,25 @@ return false; } +bool SystemZAsmParser::ParseGNUAttribute(SMLoc L) { + int64_t Tag; + int64_t IntegerValue; + if (!Parser.parseGNUAttribute(L, Tag, IntegerValue)) + return false; + + // Tag_GNU_S390_ABI_Vector tag is '8' and can be 0, 1, or 2. + if (Tag != 8 || (IntegerValue < 0 || IntegerValue > 2)) { + Error(Parser.getTok().getLoc(), + "Unrecognized .gnu_attribute tag/value pair."); + return false; + } + + Parser.getStreamer().emitGNUAttribute(Tag, IntegerValue); + + return true; +} + + bool SystemZAsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc, bool RestoreOnFailure) { Register Reg; Index: llvm/lib/Target/SystemZ/SystemZAsmPrinter.h =================================================================== --- llvm/lib/Target/SystemZ/SystemZAsmPrinter.h +++ llvm/lib/Target/SystemZ/SystemZAsmPrinter.h @@ -49,6 +49,7 @@ void LowerFENTRY_CALL(const MachineInstr &MI, SystemZMCInstLower &MCIL); void LowerSTACKMAP(const MachineInstr &MI); void LowerPATCHPOINT(const MachineInstr &MI, SystemZMCInstLower &Lower); + void emitAttributes(Module &M); }; } // end namespace llvm Index: llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp =================================================================== --- llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ llvm/lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -698,6 +698,84 @@ getSubtargetInfo()); } +// Returns true the first time Ty is passed and found to be or contain a +// vector type. +bool static isVectorTypeBased(Type *Ty, std::set &Visited) { + if (!Visited.insert(Ty).second) // Avoid infinite recursion via pointers. + return false; + if (Ty->isVectorTy()) + return true; + if (auto *PTy = dyn_cast(Ty)) + return isVectorTypeBased(PTy->getElementType(), Visited); + if (auto *ArrayTy = dyn_cast(Ty)) + return isVectorTypeBased(ArrayTy->getElementType(), Visited); + if (auto *STy = dyn_cast(Ty)) { + for (StructType::element_iterator I = STy->element_begin(), + E = STy->element_end(); I != E; ++I) + if (isVectorTypeBased(*I, Visited)) + return true; + } + if (auto *FTy = dyn_cast(Ty)) { + if (isVectorTypeBased(FTy->getReturnType(), Visited)) + return true; + for (auto I = FTy->param_begin(), E = FTy->param_end(); I != E; ++I) + if (isVectorTypeBased(*I, Visited)) + return true; + } + + return false; +} + +// The *alignment* of 128-bit vector types is different between the software +// / hardware vector ABIs, so it is needed to find out if the there is an +// externally visible use of a vector type in the module. The output file +// should then be annotated with a gnu attribute (vector ABI). +void SystemZAsmPrinter::emitAttributes(Module &M) { + std::set VisitedTypes; + bool HasVectorABI = false; + for (const GlobalValue &GV : M.global_values()) { + if (!GV.hasLocalLinkage() && (!GV.isDeclaration() || !GV.use_empty())) { + if (const Function *F = dyn_cast(&GV)) { + FunctionType *FTy = F->getFunctionType(); + if (isVectorTypeBased(FTy->getReturnType(), VisitedTypes)) + HasVectorABI = true; + else { + for (auto ParamTy : FTy->params()) + if (isVectorTypeBased(ParamTy, VisitedTypes)) { + HasVectorABI = true; + break; + } + } + if (!HasVectorABI && FTy->isVarArg()) { + for (auto U : F->users()) { + if (auto *CI = dyn_cast(&*U)) { + for (const Use &Arg : CI->args()) + if (isVectorTypeBased(Arg->getType(), VisitedTypes)) { + HasVectorABI = true; + break; + } + } + if (HasVectorABI) + break; + } + } + } + else if (const GlobalVariable *GVar = dyn_cast(&GV)) + if (isVectorTypeBased(GVar->getValueType(), VisitedTypes)) + HasVectorABI = true; + + if (HasVectorABI) + break; + } + } + + if (HasVectorABI) { + bool HasVectorFeature = + TM.getMCSubtargetInfo()->getFeatureBits()[SystemZ::FeatureVector]; + OutStreamer->emitGNUAttribute(8, HasVectorFeature ? 2 : 1); + } +} + // Convert a SystemZ-specific constant pool modifier into the associated // MCSymbolRefExpr variant kind. static MCSymbolRefExpr::VariantKind @@ -746,6 +824,7 @@ } void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) { + emitAttributes(M); emitStackMaps(SM); } Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-00.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-00.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Call to external function with vector argument. +define internal void @fun() { +entry: + tail call void @foo(<4 x i32> zeroinitializer) + ret void +} + +declare void @foo(<4 x i32>) + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-01.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-01.ll @@ -0,0 +1,16 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Call to external function with vector return value. +define internal void @fun() { +entry: + %indirect-arg-temp = alloca <4 x i32>, align 16 + %C = call <4 x i32> @foo() + store <4 x i32> %C, <4 x i32>* %indirect-arg-temp + ret void +} + +declare <4 x i32> @foo() + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-02.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-02.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Call to external function *without* vector arguments. +define internal void @fun() { +entry: + tail call void @foo(i64 0) + ret void +} + +declare void @foo(i64) + +; CHECK-NOT: .gnu_attribute 8 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-03.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-03.ll @@ -0,0 +1,11 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Defining globally visible function with vector arguments. +define <4 x i32> @fun(<4 x i32> %Arg) { +entry: + ret <4 x i32> %Arg +} + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-04.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-04.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Calling globally visible function with vector parameter. +define void @fun() { +entry: + tail call void @foo(<4 x i32> zeroinitializer) + ret void +} + +declare void @foo(<4 x i32>) + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-05.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-05.ll @@ -0,0 +1,8 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch10 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Globally visible vector variable. +@VisibleVector = global <4 x i32> zeroinitializer + +; CHECK: .gnu_attribute 8, 1 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-06.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-06.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Using external vector variable. +@ExtVector = external global <4 x i32> + +define void @fun() { +entry: + store <4 x i32> zeroinitializer, <4 x i32>* @ExtVector + ret void +} + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-07.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-07.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Using local vector variable. +@LocVector = internal global <4 x i32> zeroinitializer + +define void @fun() { +entry: + store volatile <4 x i32> zeroinitializer, <4 x i32>* @LocVector + ret void +} + +; CHECK-NOT: .gnu_attribute 8 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-08.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-08.ll @@ -0,0 +1,17 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch10 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Calling local function with vector return value. +define void @fun() { +entry: + %indirect-arg-temp = alloca <4 x i32>, align 16 + store <4 x i32> zeroinitializer, <4 x i32>* %indirect-arg-temp + call void @foo(<4 x i32>* nonnull %indirect-arg-temp) + ret void +} + +define internal void @foo(<4 x i32>*) { ret void } + +; CHECK-LABEL: fun: +; CHECK-NOT: .gnu_attribute 8 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-09.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-09.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch10 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Call to vararg function *without* any vector argument. +define internal void @fun() { +entry: + call void (...) @foo() + ret void +} + +declare void @foo(...) + +; CHECK-NOT: .gnu_attribute 8 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-10.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-10.ll @@ -0,0 +1,14 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Call to vararg function with a vector argument. +define internal void @fun() { +entry: + call void (...) @foo(<2 x i64> zeroinitializer) + ret void +} + +declare void @foo(...) + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-11.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-11.ll @@ -0,0 +1,15 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Passing address of an array of vectors. +define internal void @fun() { +entry: + %V = alloca [2 x <4 x i32>], align 16 + call void (...) @foo([2 x <4 x i32>]* nonnull %V) + ret void +} + +declare void @foo(...) + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-12.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-12.ll @@ -0,0 +1,16 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch10 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Passing a struct containing a vector element. +%struct.S = type { <4 x i32>, i32, [12 x i8] } +define internal void @fun() { +entry: + %V = alloca %struct.S, align 16 + call void (...) @foo(%struct.S* nonnull %V) + ret void +} + +declare void @foo(...) + +; CHECK: .gnu_attribute 8, 1 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-13.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-13.ll @@ -0,0 +1,18 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch10 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Call via global function pointer in internal function. + +@foo = global void (<4 x i32>*)* null, align 8 + +define internal void @fun() { +entry: + %V = alloca <4 x i32>, align 16 + store <4 x i32> zeroinitializer, <4 x i32>* %V, align 16 + %FuncPtr = load void (<4 x i32>*)*, void (<4 x i32>*)** @foo, align 8 + call void %FuncPtr(<4 x i32>* nonnull %V) + ret void +} + +; CHECK: .gnu_attribute 8, 1 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-14.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-14.ll @@ -0,0 +1,21 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Passing address of local function to called global function. + +define void @fun() { +entry: + tail call void @GlobFun(void (<4 x i32>*)* nonnull @InternalFun) + ret void +} + +declare void @GlobFun(void (<4 x i32>*)*) + +define internal void @InternalFun(<4 x i32>* nocapture %V) { +entry: + store <4 x i32> zeroinitializer, <4 x i32>* %V, align 8 + ret void +} + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/MC/SystemZ/gnu-attributes.s =================================================================== --- /dev/null +++ llvm/test/MC/SystemZ/gnu-attributes.s @@ -0,0 +1,17 @@ +# RUN: llvm-mc -triple s390x-linux-gnu -filetype=asm %s | \ +# RUN: FileCheck %s --check-prefix=ASM +# RUN: llvm-mc -triple s390x-linux-gnu -filetype=obj %s | \ +# RUN: llvm-objdump --mcpu=z14 -D - | FileCheck %s --check-prefix=OBJ + +#ASM: .text +#ASM: .gnu_attribute 8, 2 + +#OBJ: 0000000000000000 <.gnu.attributes>: +#OBJ: 0: 41 00 00 00 +#OBJ: 4: 0f 67 +#OBJ: 6: 6e 75 00 01 +#OBJ: a: 00 00 +#OBJ: c: 00 07 +#OBJ: e: 08 02 + + .gnu_attribute 8, 2