Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -7564,6 +7564,10 @@ bool IsVector = false; CharUnits UnpaddedSize; CharUnits DirectAlign; + llvm::Module &M = CGF.CGM.getModule(); + if (!CGF.CurFn->hasLocalLinkage() && ArgTy->isVectorTy() && + !M.getModuleFlag("visible-vector-ABI")) + M.addModuleFlag(llvm::Module::Warning, "visible-vector-ABI", 1); if (IsIndirect) { DirectTy = llvm::PointerType::getUnqual(DirectTy); UnpaddedSize = DirectAlign = CharUnits::fromQuantity(8); Index: clang/test/CodeGen/SystemZ/systemz-abi-vector2.c =================================================================== --- /dev/null +++ clang/test/CodeGen/SystemZ/systemz-abi-vector2.c @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -triple s390x-ibm-linux -target-cpu arch10 -emit-llvm \ +// RUN: -fzvector -o - %s 2>&1 | FileCheck %s --check-prefix=ARCH10-ATTR +// RUN: %clang_cc1 -triple s390x-ibm-linux -target-cpu arch13 -emit-llvm \ +// RUN: -fzvector -o - %s 2>&1 | FileCheck %s --check-prefix=ARCH13-ATTR + +// RUN: %clang_cc1 -triple s390x-ibm-linux -target-cpu arch10 -S \ +// RUN: -fzvector -o - %s 2>&1 | FileCheck %s --check-prefix=ARCH10-ASM +// RUN: %clang_cc1 -triple s390x-ibm-linux -target-cpu arch13 -S \ +// RUN: -fzvector -o - %s 2>&1 | FileCheck %s --check-prefix=ARCH13-ASM + +// Use of va_arg with a vector type exposes the vector ABI. + +#include + +int fun(va_list vl) { + return va_arg(vl, vector int)[0]; +} + + +//ARCH10-ATTR: !llvm.module.flags = !{!0, !1} +//ARCH10-ATTR: !0 = !{i32 2, !"visible-vector-ABI", i32 1} +//ARCH13-ATTR: !llvm.module.flags = !{!0, !1} +//ARCH13-ATTR: !0 = !{i32 2, !"visible-vector-ABI", i32 1} + +//ARCH10-ASM: .gnu_attribute 8, 1 +//ARCH13-ASM: .gnu_attribute 8, 2 Index: llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp =================================================================== --- llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -432,6 +432,7 @@ bool ParseDirectiveInsn(SMLoc L); bool ParseDirectiveMachine(SMLoc L); + bool ParseGNUAttribute(SMLoc L); OperandMatchResultTy parseAddress(OperandVector &Operands, MemoryKind MemKind, @@ -1224,6 +1225,8 @@ return ParseDirectiveInsn(DirectiveID.getLoc()); if (IDVal == ".machine") return ParseDirectiveMachine(DirectiveID.getLoc()); + if (IDVal.startswith(".gnu_attribute")) + return ParseGNUAttribute(DirectiveID.getLoc()); return true; } @@ -1358,6 +1361,24 @@ 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 @@ -70,6 +70,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 @@ -15,6 +15,7 @@ #include "MCTargetDesc/SystemZInstPrinter.h" #include "SystemZConstantPoolValue.h" #include "SystemZMCInstLower.h" +#include "SystemZMachineFunctionInfo.h" #include "TargetInfo/SystemZTargetInfo.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" @@ -757,6 +758,67 @@ getSubtargetInfo()); } +// Returns true (the first time) when Ty is found to be or contain a vector +// type. +bool llvm::SystemZ::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->getPointerElementType(), 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 +// and hardware vector ABIs. If the there is an externally visible use of a +// vector type in the module it should be annotated with an attribute. +void SystemZAsmPrinter::emitAttributes(Module &M) { + std::set VisitedTypes; + bool HasVectorABI = M.getModuleFlag("visible-vector-ABI"); + + if (!HasVectorABI) { + for (const GlobalValue &GV : M.global_values()) { + // Externally visible function definitions. + if (const Function *F = dyn_cast(&GV)) + if (!F->hasLocalLinkage() && !F->isDeclaration() && + SystemZ::isVectorTypeBased(F->getFunctionType(), VisitedTypes)) { + HasVectorABI = true; + break; + } + // Externally visible variables. + if (isa(GV) && !GV.hasLocalLinkage() && + (!GV.isDeclaration() || !GV.use_empty()) && + SystemZ::isVectorTypeBased(GV.getValueType(), VisitedTypes)) { + HasVectorABI = true; + 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 @@ -816,6 +878,7 @@ } void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) { + emitAttributes(M); emitStackMaps(SM); } Index: llvm/lib/Target/SystemZ/SystemZISelLowering.cpp =================================================================== --- llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -1608,6 +1608,32 @@ return true; } +static bool hasVisibleVectorABI(SystemZTargetLowering::CallLoweringInfo &CLI) { + Value *Callee = CLI.CB->getCalledOperand(); + bool LocalCallee = false; + if (const Function *F = dyn_cast(Callee)) + LocalCallee = F->hasLocalLinkage(); + + std::set VisitedTypes; + if (!LocalCallee && + SystemZ::isVectorTypeBased(Callee->getType(), VisitedTypes)) + // External or indirect function call. + return true; + else if (CLI.IsVarArg) { + // Check the passed varargs. Do this as well in case of a local callee as + // va_list may be passed on by it but cannot be identified as a parameter + // by isVectorTypeBased(). + for (unsigned Idx = CLI.CB->getFunctionType()->getNumParams(); + Idx < CLI.CB->arg_size(); Idx++) { + Type *ArgTy = CLI.CB->getArgOperand(Idx)->getType(); + if (SystemZ::isVectorTypeBased(ArgTy, VisitedTypes)) + return true; + } + } + + return false; +} + SDValue SystemZTargetLowering::LowerCall(CallLoweringInfo &CLI, SmallVectorImpl &InVals) const { @@ -1622,6 +1648,7 @@ CallingConv::ID CallConv = CLI.CallConv; bool IsVarArg = CLI.IsVarArg; MachineFunction &MF = DAG.getMachineFunction(); + Module &M = *MF.getFunction().getParent(); EVT PtrVT = getPointerTy(MF.getDataLayout()); LLVMContext &Ctx = *DAG.getContext(); SystemZCallingConventionRegisters *Regs = Subtarget.getSpecialRegisters(); @@ -1636,6 +1663,10 @@ VerifyVectorTypes(Ins); } + if (!M.getModuleFlag("visible-vector-ABI") && CLI.CB && + hasVisibleVectorABI(CLI)) + M.addModuleFlag(llvm::Module::Warning, "visible-vector-ABI", 1); + // Analyze the operands of the call, assigning locations to each operand. SmallVector ArgLocs; SystemZCCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, Ctx); Index: llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h =================================================================== --- llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h +++ llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h @@ -22,6 +22,8 @@ unsigned GPROffset; GPRRegs() : LowGPR(0), HighGPR(0), GPROffset(0) {} }; + + bool isVectorTypeBased(Type *Ty, std::set &Visited); } class SystemZMachineFunctionInfo : public MachineFunctionInfo { 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,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 argument. +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-04.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-04.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-05.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-05.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 with vector arg to 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/CodeGen/SystemZ/vec-abi-gnuattr-06.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-06.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 ([2 x <4 x i32>]*) @foo([2 x <4 x i32>]* nonnull %V) + ret void +} + +declare void @foo([2 x <4 x i32>]* %V) + +; 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,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 (%struct.S*) @foo(%struct.S* nonnull %V) + ret void +} + +declare void @foo(%struct.S*) + +; CHECK: .gnu_attribute 8, 1 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-08.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-08.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-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(i32 0) + 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,16 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch10 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Call to varargs function via global pointer to pointer to function. + +@fptrp = common global void (i32, ...)** null, align 8 + +define void @fun() { + %1 = load void (i32, ...)**, void (i32, ...)*** @fptrp, align 8 + %2 = load void (i32, ...)*, void (i32, ...)** %1, align 8 + tail call void (i32, ...) %2(i32 signext 0, <4 x i32> zeroinitializer) + ret void +} + +; CHECK: .gnu_attribute 8, 1 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-11.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-11.ll @@ -0,0 +1,13 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Passing vector argument to varargs function via local function pointer. + +define void @fun(void (i32, ...)* nocapture %fptr) { +entry: + tail call void (i32, ...) %fptr(i32 signext 0, <4 x i32> zeroinitializer) + ret void +} + +; 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,18 @@ +; RUN: llc -mtriple=s390x-linux-gnu -mcpu=arch13 < %s | FileCheck %s +; +; Test the emission of a .gnu_attribute describing the vector abi. + +; Passing a vararg vector argument should always emit the gnu attribute as +; the va_list may potentially be passed on to another (global) function. + +define internal void @foo(i32 %a, ...) { +entry: + ret void +} + +define internal void @fun() { + call void (i32, ...) @foo(i32 1, <4 x i32> zeroinitializer); + ret void +} + +; CHECK: .gnu_attribute 8, 2 Index: llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-13.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-13.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-14.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-14.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-15.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-15.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-16.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/SystemZ/vec-abi-gnuattr-16.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/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