Index: llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp =================================================================== --- llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp +++ llvm/lib/Target/SystemZ/MCTargetDesc/SystemZMCTargetDesc.cpp @@ -9,10 +9,13 @@ #include "SystemZMCTargetDesc.h" #include "SystemZInstPrinter.h" #include "SystemZMCAsmInfo.h" +#include "SystemZTargetStreamer.h" #include "TargetInfo/SystemZTargetInfo.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Support/TargetRegistry.h" @@ -182,6 +185,46 @@ return new SystemZInstPrinter(MAI, MII, MRI); } +class SystemZTargetAsmStreamer : public SystemZTargetStreamer { +formatted_raw_ostream &OS; +public: + SystemZTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS) + : SystemZTargetStreamer(S), OS(OS) {} + void emitGnuAttribute(unsigned Tag, unsigned Value) override { + OS << "\t.gnu_attribute " << Tag << ", " << Value << "\n"; + } +}; + +class SystemZTargetELFStreamer : public SystemZTargetStreamer { +public: + SystemZTargetELFStreamer(MCStreamer &S) : SystemZTargetStreamer(S) {} + void emitGnuAttribute(unsigned Tag, unsigned Value) override { + MCStreamer *OutStreamer = &getStreamer(); + MCSectionSubPair Current = OutStreamer->getCurrentSection(); + MCSectionELF *Section = OutStreamer->getContext().getELFSection( + ".gnu_attribute", ELF::SHT_GNU_ATTRIBUTES, 0); + OutStreamer->SwitchSection(Section); + OutStreamer->emitInt32(1090519040); + OutStreamer->emitInt32(258436725); + OutStreamer->emitInt32(65536); + OutStreamer->emitInt16(7); + OutStreamer->emitInt8(Tag); + OutStreamer->emitInt8(Value); + OutStreamer->SwitchSection(Current.first, Current.second); + } +}; + +static MCTargetStreamer * +createAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS, + MCInstPrinter *InstPrint, bool isVerboseAsm) { + return new SystemZTargetAsmStreamer(S, OS); +} + +static MCTargetStreamer * +createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { + return new SystemZTargetELFStreamer(S); +} + extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSystemZTargetMC() { // Register the MCAsmInfo. TargetRegistry::RegisterMCAsmInfo(getTheSystemZTarget(), @@ -210,4 +253,12 @@ // Register the MCInstPrinter. TargetRegistry::RegisterMCInstPrinter(getTheSystemZTarget(), createSystemZMCInstPrinter); + + // Register the asm streamer. + TargetRegistry::RegisterAsmTargetStreamer(getTheSystemZTarget(), + createAsmTargetStreamer); + + // Register the obj streamer + TargetRegistry::RegisterObjectTargetStreamer(getTheSystemZTarget(), + createObjectTargetStreamer); } 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 emitGNUAttributes(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 "SystemZTargetStreamer.h" #include "TargetInfo/SystemZTargetInfo.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" @@ -698,6 +699,63 @@ getSubtargetInfo()); } +// The *alignment* of 128-bit vector types is different between the +// software/hardware vector ABIs. +bool static isVectorOrVectorPtrType(Type *Ty) { + if (Ty->isVectorTy()) + return true; + if (auto *PTy = dyn_cast(Ty)) + return isVectorOrVectorPtrType(PTy->getElementType()); + return false; +} + +void SystemZAsmPrinter::emitGNUAttributes(Module &M) { + 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 (isVectorOrVectorPtrType(FTy->getReturnType())) + HasVectorABI = true; + else { + for (auto ParamTy : FTy->params()) + if (isVectorOrVectorPtrType(ParamTy)) { + 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 (isVectorOrVectorPtrType(Arg->getType())) { + HasVectorABI = true; + break; + } + } + if (HasVectorABI) + break; + } + } + } + else if (const GlobalVariable *GVar = dyn_cast(&GV)) + if (isVectorOrVectorPtrType(GVar->getValueType())) + HasVectorABI = true; + + if (HasVectorABI) + break; + } + } + + if (HasVectorABI) { + bool HasVectorFeature = + TM.getMCSubtargetInfo()->getFeatureBits()[SystemZ::FeatureVector]; + SystemZTargetStreamer *SZTS = + static_cast(OutStreamer->getTargetStreamer()); + SZTS->emitGnuAttribute(8, HasVectorFeature ? 2 : 1); + } +} + // Convert a SystemZ-specific constant pool modifier into the associated // MCSymbolRefExpr variant kind. static MCSymbolRefExpr::VariantKind @@ -746,6 +804,7 @@ } void SystemZAsmPrinter::emitEndOfAsmFile(Module &M) { + emitGNUAttributes(M); emitStackMaps(SM); } Index: llvm/lib/Target/SystemZ/SystemZTargetStreamer.h =================================================================== --- /dev/null +++ llvm/lib/Target/SystemZ/SystemZTargetStreamer.h @@ -0,0 +1,26 @@ +//=- SystemZTargetStreamer.h - SystemZ Target Streamer ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZTARGETSTREAMER_H +#define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZTARGETSTREAMER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/MC/MCStreamer.h" + +namespace llvm { + +class SystemZTargetStreamer : public MCTargetStreamer { +public: + SystemZTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {} + + virtual void emitGnuAttribute(unsigned Tag, unsigned Value) = 0; +}; + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZTARGETSTREAMER_H 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