[llvm] b4b4950 - [SystemZ] Allow fp/int casting with inline assembly operands.

Jonas Paulsson via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 24 11:57:41 PDT 2023


Author: Jonas Paulsson
Date: 2023-03-24T19:57:25+01:00
New Revision: b4b4950f7f71c9f3bca457ddd1ca76da001a16fa

URL: https://github.com/llvm/llvm-project/commit/b4b4950f7f71c9f3bca457ddd1ca76da001a16fa
DIFF: https://github.com/llvm/llvm-project/commit/b4b4950f7f71c9f3bca457ddd1ca76da001a16fa.diff

LOG: [SystemZ] Allow fp/int casting with inline assembly operands.

Support bitcasting between int/fp/vector values and 'r'/'f'/'v' inline
assembly operands. This is intended to match GCCs beahvior.

Reviewed By: Ulrich Weigand

Differential Revision: https://reviews.llvm.org/D146059

Added: 
    llvm/test/CodeGen/SystemZ/inline-asm-f-constraint-softfloat.ll
    llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting-explicit-regs-zEC12.ll
    llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting-explicit-regs.ll
    llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting-zEC12.ll
    llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting.ll
    llvm/test/CodeGen/SystemZ/inline-asm-v-constraint-novecfacility.ll

Modified: 
    llvm/lib/Target/SystemZ/SystemZISelLowering.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
index dd5b885701fa..3b7b0a1b60e7 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
@@ -1105,19 +1105,18 @@ getSingleConstraintMatchWeight(AsmOperandInfo &info,
   case 'd': // Data register (equivalent to 'r')
   case 'h': // High-part register
   case 'r': // General-purpose register
-    if (CallOperandVal->getType()->isIntegerTy())
-      weight = CW_Register;
+    weight = CallOperandVal->getType()->isIntegerTy() ? CW_Register : CW_Default;
     break;
 
   case 'f': // Floating-point register
-    if (type->isFloatingPointTy())
-      weight = CW_Register;
+    if (!useSoftFloat())
+      weight = type->isFloatingPointTy() ? CW_Register : CW_Default;
     break;
 
   case 'v': // Vector register
-    if ((type->isVectorTy() || type->isFloatingPointTy()) &&
-        Subtarget.hasVector())
-      weight = CW_Register;
+    if (Subtarget.hasVector())
+      weight = (type->isVectorTy() || type->isFloatingPointTy()) ? CW_Register
+                                                                 : CW_Default;
     break;
 
   case 'I': // Unsigned 8-bit constant
@@ -1179,9 +1178,9 @@ SystemZTargetLowering::getRegForInlineAsmConstraint(
     default: break;
     case 'd': // Data register (equivalent to 'r')
     case 'r': // General-purpose register
-      if (VT == MVT::i64)
+      if (VT.getSizeInBits() == 64)
         return std::make_pair(0U, &SystemZ::GR64BitRegClass);
-      else if (VT == MVT::i128)
+      else if (VT.getSizeInBits() == 128)
         return std::make_pair(0U, &SystemZ::GR128BitRegClass);
       return std::make_pair(0U, &SystemZ::GR32BitRegClass);
 
@@ -1197,18 +1196,19 @@ SystemZTargetLowering::getRegForInlineAsmConstraint(
 
     case 'f': // Floating-point register
       if (!useSoftFloat()) {
-        if (VT == MVT::f64)
+        if (VT.getSizeInBits() == 64)
           return std::make_pair(0U, &SystemZ::FP64BitRegClass);
-        else if (VT == MVT::f128)
+        else if (VT.getSizeInBits() == 128)
           return std::make_pair(0U, &SystemZ::FP128BitRegClass);
         return std::make_pair(0U, &SystemZ::FP32BitRegClass);
       }
       break;
+
     case 'v': // Vector register
       if (Subtarget.hasVector()) {
-        if (VT == MVT::f32)
+        if (VT.getSizeInBits() == 32)
           return std::make_pair(0U, &SystemZ::VR32BitRegClass);
-        if (VT == MVT::f64)
+        if (VT.getSizeInBits() == 64)
           return std::make_pair(0U, &SystemZ::VR64BitRegClass);
         return std::make_pair(0U, &SystemZ::VR128BitRegClass);
       }
@@ -1216,15 +1216,22 @@ SystemZTargetLowering::getRegForInlineAsmConstraint(
     }
   }
   if (Constraint.size() > 0 && Constraint[0] == '{') {
+
+    // A clobber constraint (e.g. ~{f0}) will have MVT::Other which is illegal
+    // to check the size on.
+    auto getVTSizeInBits = [&VT]() {
+      return VT == MVT::Other ? 0 : VT.getSizeInBits();
+    };
+
     // We need to override the default register parsing for GPRs and FPRs
     // because the interpretation depends on VT.  The internal names of
     // the registers are also 
diff erent from the external names
     // (F0D and F0S instead of F0, etc.).
     if (Constraint[1] == 'r') {
-      if (VT == MVT::i32)
+      if (getVTSizeInBits() == 32)
         return parseRegisterNumber(Constraint, &SystemZ::GR32BitRegClass,
                                    SystemZMC::GR32Regs, 16);
-      if (VT == MVT::i128)
+      if (getVTSizeInBits() == 128)
         return parseRegisterNumber(Constraint, &SystemZ::GR128BitRegClass,
                                    SystemZMC::GR128Regs, 16);
       return parseRegisterNumber(Constraint, &SystemZ::GR64BitRegClass,
@@ -1234,10 +1241,10 @@ SystemZTargetLowering::getRegForInlineAsmConstraint(
       if (useSoftFloat())
         return std::make_pair(
             0u, static_cast<const TargetRegisterClass *>(nullptr));
-      if (VT == MVT::f32)
+      if (getVTSizeInBits() == 32)
         return parseRegisterNumber(Constraint, &SystemZ::FP32BitRegClass,
                                    SystemZMC::FP32Regs, 16);
-      if (VT == MVT::f128)
+      if (getVTSizeInBits() == 128)
         return parseRegisterNumber(Constraint, &SystemZ::FP128BitRegClass,
                                    SystemZMC::FP128Regs, 16);
       return parseRegisterNumber(Constraint, &SystemZ::FP64BitRegClass,
@@ -1247,10 +1254,10 @@ SystemZTargetLowering::getRegForInlineAsmConstraint(
       if (!Subtarget.hasVector())
         return std::make_pair(
             0u, static_cast<const TargetRegisterClass *>(nullptr));
-      if (VT == MVT::f32)
+      if (getVTSizeInBits() == 32)
         return parseRegisterNumber(Constraint, &SystemZ::VR32BitRegClass,
                                    SystemZMC::VR32Regs, 32);
-      if (VT == MVT::f64)
+      if (getVTSizeInBits() == 64)
         return parseRegisterNumber(Constraint, &SystemZ::VR64BitRegClass,
                                    SystemZMC::VR64Regs, 32);
       return parseRegisterNumber(Constraint, &SystemZ::VR128BitRegClass,
@@ -1453,28 +1460,24 @@ bool SystemZTargetLowering::splitValueIntoRegisterParts(
     SelectionDAG &DAG, const SDLoc &DL, SDValue Val, SDValue *Parts,
     unsigned NumParts, MVT PartVT, std::optional<CallingConv::ID> CC) const {
   EVT ValueVT = Val.getValueType();
-  assert((ValueVT != MVT::i128 ||
-          ((NumParts == 1 && PartVT == MVT::Untyped) ||
-           (NumParts == 2 && PartVT == MVT::i64))) &&
-         "Unknown handling of i128 value.");
-  if (ValueVT == MVT::i128 && NumParts == 1) {
+  if (ValueVT.getSizeInBits() == 128 && NumParts == 1 && PartVT == MVT::Untyped) {
     // Inline assembly operand.
-    Parts[0] = lowerI128ToGR128(DAG, Val);
+    Parts[0] = lowerI128ToGR128(DAG, DAG.getBitcast(MVT::i128, Val));
     return true;
   }
+
   return false;
 }
 
 SDValue SystemZTargetLowering::joinRegisterPartsIntoValue(
     SelectionDAG &DAG, const SDLoc &DL, const SDValue *Parts, unsigned NumParts,
     MVT PartVT, EVT ValueVT, std::optional<CallingConv::ID> CC) const {
-  assert((ValueVT != MVT::i128 ||
-          ((NumParts == 1 && PartVT == MVT::Untyped) ||
-           (NumParts == 2 && PartVT == MVT::i64))) &&
-         "Unknown handling of i128 value.");
-  if (ValueVT == MVT::i128 && NumParts == 1)
+  if (ValueVT.getSizeInBits() == 128 && NumParts == 1 && PartVT == MVT::Untyped) {
     // Inline assembly operand.
-    return lowerGR128ToI128(DAG, Parts[0]);
+    SDValue Res = lowerGR128ToI128(DAG, Parts[0]);
+    return DAG.getBitcast(ValueVT, Res);
+  }
+
   return SDValue();
 }
 

diff  --git a/llvm/test/CodeGen/SystemZ/inline-asm-f-constraint-softfloat.ll b/llvm/test/CodeGen/SystemZ/inline-asm-f-constraint-softfloat.ll
new file mode 100644
index 000000000000..b36c41046244
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/inline-asm-f-constraint-softfloat.ll
@@ -0,0 +1,9 @@
+; RUN: not llc -mtriple=s390x-linux-gnu -mcpu=z15 -mattr=soft-float < %s 2>&1 | FileCheck %s
+
+; CHECK: error: couldn't allocate output register for constraint 'f'
+
+define signext i32 @int_and_f(i32 signext %cc_dep1) {
+entry:
+  %0 = tail call i32 asm sideeffect "", "=f,0"(i32 %cc_dep1)
+  ret i32 %0
+}

diff  --git a/llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting-explicit-regs-zEC12.ll b/llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting-explicit-regs-zEC12.ll
new file mode 100644
index 000000000000..44175f924f7f
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting-explicit-regs-zEC12.ll
@@ -0,0 +1,206 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -mtriple=s390x-linux-gnu -mcpu=zEC12 < %s | FileCheck %s
+;
+; Test inline assembly where the operand is bitcasted.
+
+define signext i32 @int_and_f(i32 signext %cc_dep1) {
+; CHECK-LABEL: int_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    risbhg %r0, %r2, 0, 159, 32
+; CHECK-NEXT:    ldgr %f1, %r0
+; CHECK-NEXT:    # kill: def $f1s killed $f1s killed $f1d
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    # kill: def $f1s killed $f1s def $f1d
+; CHECK-NEXT:    lgdr %r0, %f1
+; CHECK-NEXT:    risblg %r0, %r0, 0, 159, 32
+; CHECK-NEXT:    lgfr %r2, %r0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i32 asm sideeffect "", "={f1},0"(i32 %cc_dep1)
+  ret i32 %0
+}
+
+define i64 @long_and_f(i64 %cc_dep1) {
+; CHECK-LABEL: long_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    ldgr %f2, %r2
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgdr %r2, %f2
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i64 asm sideeffect "", "={f2},0"(i64 %cc_dep1)
+  ret i64 %0
+}
+
+define void @__int128_and_f(ptr noalias nocapture writeonly sret(i128) align 8 %agg.result, ptr %0) {
+; CHECK-LABEL: __int128_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    ld %f1, 0(%r3)
+; CHECK-NEXT:    ld %f3, 8(%r3)
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    std %f1, 0(%r2)
+; CHECK-NEXT:    std %f3, 8(%r2)
+; CHECK-NEXT:    br %r14
+entry:
+  %cc_dep1 = load i128, ptr %0, align 8
+  %1 = tail call i128 asm sideeffect "", "={f1},0"(i128 %cc_dep1)
+  store i128 %1, ptr %agg.result, align 8
+  ret void
+}
+
+define float @float_and_r(float %cc_dep1) {
+; CHECK-LABEL: float_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    # kill: def $f0s killed $f0s def $f0d
+; CHECK-NEXT:    lgdr %r0, %f0
+; CHECK-NEXT:    risblg %r2, %r0, 0, 159, 32
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    risbhg %r0, %r2, 0, 159, 32
+; CHECK-NEXT:    ldgr %f0, %r0
+; CHECK-NEXT:    # kill: def $f0s killed $f0s killed $f0d
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call float asm sideeffect "", "={r2},0"(float %cc_dep1)
+  ret float %0
+}
+
+define double @double_and_r(double %cc_dep1) {
+; CHECK-LABEL: double_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    lgdr %r3, %f0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    ldgr %f0, %r3
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call double asm sideeffect "", "={r3},0"(double %cc_dep1)
+  ret double %0
+}
+
+define void @longdouble_and_r(ptr noalias nocapture writeonly sret(fp128) align 8 %agg.result, ptr %0) {
+; CHECK-LABEL: longdouble_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    lg %r5, 8(%r3)
+; CHECK-NEXT:    lg %r4, 0(%r3)
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    stg %r5, 8(%r2)
+; CHECK-NEXT:    stg %r4, 0(%r2)
+; CHECK-NEXT:    br %r14
+entry:
+  %cc_dep1 = load fp128, ptr %0, align 8
+  %1 = tail call fp128 asm sideeffect "", "={r4},0"(fp128 %cc_dep1)
+  store fp128 %1, ptr %agg.result, align 8
+  ret void
+}
+
+define <2 x i16> @vec32_and_r(<2 x i16> %cc_dep1) {
+; CHECK-LABEL: vec32_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    # kill: def $r3l killed $r3l def $r3d
+; CHECK-NEXT:    # kill: def $r2l killed $r2l def $r2d
+; CHECK-NEXT:    risbgn %r3, %r2, 32, 47, 16
+; CHECK-NEXT:    # kill: def $r3l killed $r3l killed $r3d
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    srlk %r2, %r3, 16
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i16> asm sideeffect "", "={r3},0"(<2 x i16> %cc_dep1)
+  ret <2 x i16> %0
+}
+
+define <2 x i32> @vec64_and_r(<2 x i32> %cc_dep1) {
+; CHECK-LABEL: vec64_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    # kill: def $r2l killed $r2l def $r2d
+; CHECK-NEXT:    sllg %r5, %r2, 32
+; CHECK-NEXT:    lr %r5, %r3
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgr %r3, %r5
+; CHECK-NEXT:    srlg %r2, %r5, 32
+; CHECK-NEXT:    # kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:    # kill: def $r3l killed $r3l killed $r3d
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i32> asm sideeffect "", "={r5},0"(<2 x i32> %cc_dep1)
+  ret <2 x i32> %0
+}
+
+define <2 x i16> @vec32_and_f(<2 x i16> %cc_dep1) {
+; CHECK-LABEL: vec32_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    # kill: def $r3l killed $r3l def $r3d
+; CHECK-NEXT:    # kill: def $r2l killed $r2l def $r2d
+; CHECK-NEXT:    risbgn %r3, %r2, 32, 47, 16
+; CHECK-NEXT:    risbhg %r0, %r3, 0, 159, 32
+; CHECK-NEXT:    ldgr %f3, %r0
+; CHECK-NEXT:    # kill: def $f3s killed $f3s killed $f3d
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    # kill: def $f3s killed $f3s def $f3d
+; CHECK-NEXT:    lgdr %r0, %f3
+; CHECK-NEXT:    risblg %r3, %r0, 0, 159, 32
+; CHECK-NEXT:    srlk %r2, %r3, 16
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i16> asm sideeffect "", "={f3},0"(<2 x i16> %cc_dep1)
+  ret <2 x i16> %0
+}
+
+define <2 x i32> @vec64_and_f(<2 x i32> %cc_dep1) {
+; CHECK-LABEL: vec64_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    # kill: def $r2l killed $r2l def $r2d
+; CHECK-NEXT:    sllg %r0, %r2, 32
+; CHECK-NEXT:    lr %r0, %r3
+; CHECK-NEXT:    ldgr %f4, %r0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgdr %r3, %f4
+; CHECK-NEXT:    srlg %r2, %r3, 32
+; CHECK-NEXT:    # kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:    # kill: def $r3l killed $r3l killed $r3d
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i32> asm sideeffect "", "={f4},0"(<2 x i32> %cc_dep1)
+  ret <2 x i32> %0
+}
+
+define <4 x i32> @vec128_and_f(<4 x i32> %cc_dep1) {
+; CHECK-LABEL: vec128_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    aghi %r15, -176
+; CHECK-NEXT:    .cfi_def_cfa_offset 336
+; CHECK-NEXT:    # kill: def $r4l killed $r4l def $r4d
+; CHECK-NEXT:    sllg %r0, %r4, 32
+; CHECK-NEXT:    lr %r0, %r5
+; CHECK-NEXT:    # kill: def $r2l killed $r2l def $r2d
+; CHECK-NEXT:    stg %r0, 168(%r15)
+; CHECK-NEXT:    sllg %r0, %r2, 32
+; CHECK-NEXT:    lr %r0, %r3
+; CHECK-NEXT:    stg %r0, 160(%r15)
+; CHECK-NEXT:    ld %f0, 160(%r15)
+; CHECK-NEXT:    ld %f2, 168(%r15)
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgdr %r3, %f0
+; CHECK-NEXT:    lgdr %r5, %f2
+; CHECK-NEXT:    srlg %r2, %r3, 32
+; CHECK-NEXT:    srlg %r4, %r5, 32
+; CHECK-NEXT:    # kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:    # kill: def $r3l killed $r3l killed $r3d
+; CHECK-NEXT:    # kill: def $r4l killed $r4l killed $r4d
+; CHECK-NEXT:    # kill: def $r5l killed $r5l killed $r5d
+; CHECK-NEXT:    aghi %r15, 176
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <4 x i32> asm sideeffect "", "={f0},0"(<4 x i32> %cc_dep1)
+  ret <4 x i32> %0
+}
+

diff  --git a/llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting-explicit-regs.ll b/llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting-explicit-regs.ll
new file mode 100644
index 000000000000..f927bdd5390f
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting-explicit-regs.ll
@@ -0,0 +1,273 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -mtriple=s390x-linux-gnu -mcpu=z15 < %s | FileCheck %s --check-prefixes=CHECK,Z15
+; RUN: llc -mtriple=s390x-linux-gnu -mcpu=z13 < %s | FileCheck %s --check-prefixes=CHECK,Z13
+;
+; Test inline assembly where the operand is bitcasted.
+
+define signext i32 @int_and_f(i32 signext %cc_dep1) {
+; CHECK-LABEL: int_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlvgf %v0, %r2, 0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlgvf %r0, %v0, 0
+; CHECK-NEXT:    lgfr %r2, %r0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i32 asm sideeffect "", "={f0},0"(i32 %cc_dep1)
+  ret i32 %0
+}
+
+define i64 @long_and_f(i64 %cc_dep1) {
+; CHECK-LABEL: long_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    ldgr %f1, %r2
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgdr %r2, %f1
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i64 asm sideeffect "", "={f1},0"(i64 %cc_dep1)
+  ret i64 %0
+}
+
+define void @__int128_and_f(ptr noalias nocapture writeonly sret(i128) align 8 %agg.result, ptr %0) {
+; Z15-LABEL: __int128_and_f:
+; Z15:       # %bb.0: # %entry
+; Z15-NEXT:    vl %v0, 0(%r3), 3
+; Z15-NEXT:    vrepg %v6, %v0, 1
+; Z15-NEXT:    vlr %v4, %v0
+; Z15-NEXT:    #APP
+; Z15-NEXT:    #NO_APP
+; Z15-NEXT:    vmrhg %v0, %v4, %v6
+; Z15-NEXT:    vst %v0, 0(%r2), 3
+; Z15-NEXT:    br %r14
+;
+; Z13-LABEL: __int128_and_f:
+; Z13:       # %bb.0: # %entry
+; Z13-NEXT:    ld %f4, 0(%r3)
+; Z13-NEXT:    ld %f6, 8(%r3)
+; Z13-NEXT:    #APP
+; Z13-NEXT:    #NO_APP
+; Z13-NEXT:    std %f4, 0(%r2)
+; Z13-NEXT:    std %f6, 8(%r2)
+; Z13-NEXT:    br %r14
+entry:
+  %cc_dep1 = load i128, ptr %0, align 8
+  %1 = tail call i128 asm sideeffect "", "={f4},0"(i128 %cc_dep1)
+  store i128 %1, ptr %agg.result, align 8
+  ret void
+}
+
+define signext i32 @int_and_v(i32 signext %cc_dep1) {
+; CHECK-LABEL: int_and_v:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlvgf %v0, %r2, 0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlgvf %r0, %v0, 0
+; CHECK-NEXT:    lgfr %r2, %r0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i32 asm sideeffect "", "={v0},0"(i32 %cc_dep1)
+  ret i32 %0
+}
+
+define i64 @long_and_v(i64 %cc_dep1) {
+; CHECK-LABEL: long_and_v:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    ldgr %f1, %r2
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgdr %r2, %f1
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i64 asm sideeffect "", "={v1},0"(i64 %cc_dep1)
+  ret i64 %0
+}
+
+define void @__int128_and_v(ptr noalias nocapture writeonly sret(i128) align 8 %agg.result, ptr %0) {
+; CHECK-LABEL: __int128_and_v:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vl %v2, 0(%r3), 3
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vst %v2, 0(%r2), 3
+; CHECK-NEXT:    br %r14
+entry:
+  %cc_dep1 = load i128, ptr %0, align 8
+  %1 = tail call i128 asm sideeffect "", "={v2},0"(i128 %cc_dep1)
+  store i128 %1, ptr %agg.result, align 8
+  ret void
+}
+
+define float @float_and_r(float %cc_dep1) {
+; CHECK-LABEL: float_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlgvf %r0, %v0, 0
+; CHECK-NEXT:    # kill: def $r0l killed $r0l killed $r0d
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlvgf %v0, %r0, 0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call float asm sideeffect "", "={r0},0"(float %cc_dep1)
+  ret float %0
+}
+
+define double @double_and_r(double %cc_dep1) {
+; CHECK-LABEL: double_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    lgdr %r1, %f0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    ldgr %f0, %r1
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call double asm sideeffect "", "={r1},0"(double %cc_dep1)
+  ret double %0
+}
+
+define void @longdouble_and_r(ptr noalias nocapture writeonly sret(fp128) align 8 %agg.result, ptr %0) {
+; CHECK-LABEL: longdouble_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    lg %r5, 8(%r3)
+; CHECK-NEXT:    lg %r4, 0(%r3)
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    stg %r5, 8(%r2)
+; CHECK-NEXT:    stg %r4, 0(%r2)
+; CHECK-NEXT:    br %r14
+entry:
+  %cc_dep1 = load fp128, ptr %0, align 8
+  %1 = tail call fp128 asm sideeffect "", "={r4},0"(fp128 %cc_dep1)
+  store fp128 %1, ptr %agg.result, align 8
+  ret void
+}
+
+define float @float_and_v(float %cc_dep1) {
+; CHECK-LABEL: float_and_v:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    ldr %f3, %f0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    ldr %f0, %f3
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call float asm sideeffect "", "={v3},0"(float %cc_dep1)
+  ret float %0
+}
+
+define double @double_and_v(double %cc_dep1) {
+; CHECK-LABEL: double_and_v:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    ldr %f4, %f0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    ldr %f0, %f4
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call double asm sideeffect "", "={v4},0"(double %cc_dep1)
+  ret double %0
+}
+
+define void @longdouble_and_v(ptr noalias nocapture writeonly sret(fp128) align 8 %agg.result, ptr %0) {
+; CHECK-LABEL: longdouble_and_v:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vl %v5, 0(%r3), 3
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vst %v5, 0(%r2), 3
+; CHECK-NEXT:    br %r14
+entry:
+  %cc_dep1 = load fp128, ptr %0, align 8
+  %1 = tail call fp128 asm sideeffect "", "={v5},0"(fp128 %cc_dep1)
+  store fp128 %1, ptr %agg.result, align 8
+  ret void
+}
+
+define <2 x i16> @vec32_and_r(<2 x i16> %cc_dep1) {
+; CHECK-LABEL: vec32_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlgvf %r5, %v24, 0
+; CHECK-NEXT:    # kill: def $r5l killed $r5l killed $r5d
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlvgf %v24, %r5, 0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i16> asm sideeffect "", "={r5},0"(<2 x i16> %cc_dep1)
+  ret <2 x i16> %0
+}
+
+define <2 x i32> @vec64_and_r(<2 x i32> %cc_dep1) {
+; CHECK-LABEL: vec64_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlgvg %r4, %v24, 0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlvgg %v24, %r4, 0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i32> asm sideeffect "", "={r4},0"(<2 x i32> %cc_dep1)
+  ret <2 x i32> %0
+}
+
+define <4 x i32> @vec128_and_r(<4 x i32> %cc_dep1) {
+; CHECK-LABEL: vec128_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlgvg %r3, %v24, 1
+; CHECK-NEXT:    vlgvg %r2, %v24, 0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlvgp %v24, %r2, %r3
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <4 x i32> asm sideeffect "", "={r2},0"(<4 x i32> %cc_dep1)
+  ret <4 x i32> %0
+}
+
+define <2 x i16> @vec32_and_f(<2 x i16> %cc_dep1) {
+; CHECK-LABEL: vec32_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlr %v4, %v24
+; CHECK-NEXT:    # kill: def $f4s killed $f4s killed $v4
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    # kill: def $f4s killed $f4s def $v4
+; CHECK-NEXT:    vlr %v24, %v4
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i16> asm sideeffect "", "={f4},0"(<2 x i16> %cc_dep1)
+  ret <2 x i16> %0
+}
+
+define <2 x i32> @vec64_and_f(<2 x i32> %cc_dep1) {
+; CHECK-LABEL: vec64_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlr %v5, %v24
+; CHECK-NEXT:    # kill: def $f5d killed $f5d killed $v5
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    # kill: def $f5d killed $f5d def $v5
+; CHECK-NEXT:    vlr %v24, %v5
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i32> asm sideeffect "", "={f5},0"(<2 x i32> %cc_dep1)
+  ret <2 x i32> %0
+}
+
+define <4 x i32> @vec128_and_f(<4 x i32> %cc_dep1) {
+; CHECK-LABEL: vec128_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vrepg %v3, %v24, 1
+; CHECK-NEXT:    vlr %v1, %v24
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vmrhg %v24, %v1, %v3
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <4 x i32> asm sideeffect "", "={f1},0"(<4 x i32> %cc_dep1)
+  ret <4 x i32> %0
+}
+

diff  --git a/llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting-zEC12.ll b/llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting-zEC12.ll
new file mode 100644
index 000000000000..1ef6eece80ac
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting-zEC12.ll
@@ -0,0 +1,201 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -mtriple=s390x-linux-gnu -mcpu=zEC12 < %s | FileCheck %s
+;
+; Test inline assembly where the operand is bitcasted.
+
+define signext i32 @int_and_f(i32 signext %cc_dep1) {
+; CHECK-LABEL: int_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    risbhg %r0, %r2, 0, 159, 32
+; CHECK-NEXT:    ldgr %f0, %r0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgdr %r0, %f0
+; CHECK-NEXT:    risblg %r0, %r0, 0, 159, 32
+; CHECK-NEXT:    lgfr %r2, %r0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i32 asm sideeffect "", "=f,0"(i32 %cc_dep1)
+  ret i32 %0
+}
+
+define i64 @long_and_f(i64 %cc_dep1) {
+; CHECK-LABEL: long_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    ldgr %f0, %r2
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgdr %r2, %f0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i64 asm sideeffect "", "=f,0"(i64 %cc_dep1)
+  ret i64 %0
+}
+
+define void @__int128_and_f(ptr noalias nocapture writeonly sret(i128) align 8 %agg.result, ptr %0) {
+; CHECK-LABEL: __int128_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    ld %f0, 0(%r3)
+; CHECK-NEXT:    ld %f2, 8(%r3)
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    std %f0, 0(%r2)
+; CHECK-NEXT:    std %f2, 8(%r2)
+; CHECK-NEXT:    br %r14
+entry:
+  %cc_dep1 = load i128, ptr %0, align 8
+  %1 = tail call i128 asm sideeffect "", "=f,0"(i128 %cc_dep1)
+  store i128 %1, ptr %agg.result, align 8
+  ret void
+}
+
+define float @float_and_r(float %cc_dep1) {
+; CHECK-LABEL: float_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    # kill: def $f0s killed $f0s def $f0d
+; CHECK-NEXT:    lgdr %r0, %f0
+; CHECK-NEXT:    risblg %r0, %r0, 0, 159, 32
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    risbhg %r0, %r0, 0, 159, 32
+; CHECK-NEXT:    ldgr %f0, %r0
+; CHECK-NEXT:    # kill: def $f0s killed $f0s killed $f0d
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call float asm sideeffect "", "=r,0"(float %cc_dep1)
+  ret float %0
+}
+
+define double @double_and_r(double %cc_dep1) {
+; CHECK-LABEL: double_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    lgdr %r0, %f0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    ldgr %f0, %r0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call double asm sideeffect "", "=r,0"(double %cc_dep1)
+  ret double %0
+}
+
+define void @longdouble_and_r(ptr noalias nocapture writeonly sret(fp128) align 8 %agg.result, ptr %0) {
+; CHECK-LABEL: longdouble_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    lg %r1, 8(%r3)
+; CHECK-NEXT:    lg %r0, 0(%r3)
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    stg %r1, 8(%r2)
+; CHECK-NEXT:    stg %r0, 0(%r2)
+; CHECK-NEXT:    br %r14
+entry:
+  %cc_dep1 = load fp128, ptr %0, align 8
+  %1 = tail call fp128 asm sideeffect "", "=r,0"(fp128 %cc_dep1)
+  store fp128 %1, ptr %agg.result, align 8
+  ret void
+}
+
+define <2 x i16> @vec32_and_r(<2 x i16> %cc_dep1) {
+; CHECK-LABEL: vec32_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    # kill: def $r3l killed $r3l def $r3d
+; CHECK-NEXT:    # kill: def $r2l killed $r2l def $r2d
+; CHECK-NEXT:    risbgn %r3, %r2, 32, 47, 16
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    srlk %r2, %r3, 16
+; CHECK-NEXT:    # kill: def $r3l killed $r3l killed $r3d
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i16> asm sideeffect "", "=r,0"(<2 x i16> %cc_dep1)
+  ret <2 x i16> %0
+}
+
+define <2 x i32> @vec64_and_r(<2 x i32> %cc_dep1) {
+; CHECK-LABEL: vec64_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    # kill: def $r2l killed $r2l def $r2d
+; CHECK-NEXT:    sllg %r0, %r2, 32
+; CHECK-NEXT:    lr %r0, %r3
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lr %r3, %r0
+; CHECK-NEXT:    srlg %r2, %r0, 32
+; CHECK-NEXT:    # kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i32> asm sideeffect "", "=r,0"(<2 x i32> %cc_dep1)
+  ret <2 x i32> %0
+}
+
+define <2 x i16> @vec32_and_f(<2 x i16> %cc_dep1) {
+; CHECK-LABEL: vec32_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    # kill: def $r3l killed $r3l def $r3d
+; CHECK-NEXT:    # kill: def $r2l killed $r2l def $r2d
+; CHECK-NEXT:    risbgn %r3, %r2, 32, 47, 16
+; CHECK-NEXT:    risbhg %r0, %r3, 0, 159, 32
+; CHECK-NEXT:    ldgr %f0, %r0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgdr %r0, %f0
+; CHECK-NEXT:    risblg %r3, %r0, 0, 159, 32
+; CHECK-NEXT:    srlk %r2, %r3, 16
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i16> asm sideeffect "", "=f,0"(<2 x i16> %cc_dep1)
+  ret <2 x i16> %0
+}
+
+define <2 x i32> @vec64_and_f(<2 x i32> %cc_dep1) {
+; CHECK-LABEL: vec64_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    # kill: def $r2l killed $r2l def $r2d
+; CHECK-NEXT:    sllg %r0, %r2, 32
+; CHECK-NEXT:    lr %r0, %r3
+; CHECK-NEXT:    ldgr %f0, %r0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgdr %r3, %f0
+; CHECK-NEXT:    srlg %r2, %r3, 32
+; CHECK-NEXT:    # kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:    # kill: def $r3l killed $r3l killed $r3d
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i32> asm sideeffect "", "=f,0"(<2 x i32> %cc_dep1)
+  ret <2 x i32> %0
+}
+
+define <4 x i32> @vec128_and_f(<4 x i32> %cc_dep1) {
+; CHECK-LABEL: vec128_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    aghi %r15, -176
+; CHECK-NEXT:    .cfi_def_cfa_offset 336
+; CHECK-NEXT:    # kill: def $r4l killed $r4l def $r4d
+; CHECK-NEXT:    sllg %r0, %r4, 32
+; CHECK-NEXT:    lr %r0, %r5
+; CHECK-NEXT:    # kill: def $r2l killed $r2l def $r2d
+; CHECK-NEXT:    stg %r0, 168(%r15)
+; CHECK-NEXT:    sllg %r0, %r2, 32
+; CHECK-NEXT:    lr %r0, %r3
+; CHECK-NEXT:    stg %r0, 160(%r15)
+; CHECK-NEXT:    ld %f0, 160(%r15)
+; CHECK-NEXT:    ld %f2, 168(%r15)
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgdr %r3, %f0
+; CHECK-NEXT:    lgdr %r5, %f2
+; CHECK-NEXT:    srlg %r2, %r3, 32
+; CHECK-NEXT:    srlg %r4, %r5, 32
+; CHECK-NEXT:    # kill: def $r2l killed $r2l killed $r2d
+; CHECK-NEXT:    # kill: def $r3l killed $r3l killed $r3d
+; CHECK-NEXT:    # kill: def $r4l killed $r4l killed $r4d
+; CHECK-NEXT:    # kill: def $r5l killed $r5l killed $r5d
+; CHECK-NEXT:    aghi %r15, 176
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <4 x i32> asm sideeffect "", "=f,0"(<4 x i32> %cc_dep1)
+  ret <4 x i32> %0
+}
+

diff  --git a/llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting.ll b/llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting.ll
new file mode 100644
index 000000000000..b953fc31f3fc
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/inline-asm-fp-int-casting.ll
@@ -0,0 +1,262 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc -mtriple=s390x-linux-gnu -mcpu=z15 < %s | FileCheck %s --check-prefixes=CHECK,Z15
+; RUN: llc -mtriple=s390x-linux-gnu -mcpu=z13 < %s | FileCheck %s --check-prefixes=CHECK,Z13
+;
+; Test inline assembly where the operand is bitcasted.
+
+define signext i32 @int_and_f(i32 signext %cc_dep1) {
+; CHECK-LABEL: int_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlvgf %v0, %r2, 0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlgvf %r0, %v0, 0
+; CHECK-NEXT:    lgfr %r2, %r0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i32 asm sideeffect "", "=f,0"(i32 %cc_dep1)
+  ret i32 %0
+}
+
+define i64 @long_and_f(i64 %cc_dep1) {
+; CHECK-LABEL: long_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    ldgr %f0, %r2
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgdr %r2, %f0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i64 asm sideeffect "", "=f,0"(i64 %cc_dep1)
+  ret i64 %0
+}
+
+define void @__int128_and_f(ptr noalias nocapture writeonly sret(i128) align 8 %agg.result, ptr %0) {
+; Z15-LABEL: __int128_and_f:
+; Z15:       # %bb.0: # %entry
+; Z15-NEXT:    vl %v0, 0(%r3), 3
+; Z15-NEXT:    vrepg %v2, %v0, 1
+; Z15-NEXT:    #APP
+; Z15-NEXT:    #NO_APP
+; Z15-NEXT:    vmrhg %v0, %v0, %v2
+; Z15-NEXT:    vst %v0, 0(%r2), 3
+; Z15-NEXT:    br %r14
+;
+; Z13-LABEL: __int128_and_f:
+; Z13:       # %bb.0: # %entry
+; Z13-NEXT:    ld %f0, 0(%r3)
+; Z13-NEXT:    ld %f2, 8(%r3)
+; Z13-NEXT:    #APP
+; Z13-NEXT:    #NO_APP
+; Z13-NEXT:    std %f0, 0(%r2)
+; Z13-NEXT:    std %f2, 8(%r2)
+; Z13-NEXT:    br %r14
+entry:
+  %cc_dep1 = load i128, ptr %0, align 8
+  %1 = tail call i128 asm sideeffect "", "=f,0"(i128 %cc_dep1)
+  store i128 %1, ptr %agg.result, align 8
+  ret void
+}
+
+define signext i32 @int_and_v(i32 signext %cc_dep1) {
+; CHECK-LABEL: int_and_v:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlvgf %v0, %r2, 0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlgvf %r0, %v0, 0
+; CHECK-NEXT:    lgfr %r2, %r0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i32 asm sideeffect "", "=v,0"(i32 %cc_dep1)
+  ret i32 %0
+}
+
+define i64 @long_and_v(i64 %cc_dep1) {
+; CHECK-LABEL: long_and_v:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    ldgr %f0, %r2
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    lgdr %r2, %f0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call i64 asm sideeffect "", "=v,0"(i64 %cc_dep1)
+  ret i64 %0
+}
+
+define void @__int128_and_v(ptr noalias nocapture writeonly sret(i128) align 8 %agg.result, ptr %0) {
+; CHECK-LABEL: __int128_and_v:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vl %v0, 0(%r3), 3
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vst %v0, 0(%r2), 3
+; CHECK-NEXT:    br %r14
+entry:
+  %cc_dep1 = load i128, ptr %0, align 8
+  %1 = tail call i128 asm sideeffect "", "=v,0"(i128 %cc_dep1)
+  store i128 %1, ptr %agg.result, align 8
+  ret void
+}
+
+define float @float_and_r(float %cc_dep1) {
+; CHECK-LABEL: float_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlgvf %r0, %v0, 0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlvgf %v0, %r0, 0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call float asm sideeffect "", "=r,0"(float %cc_dep1)
+  ret float %0
+}
+
+define double @double_and_r(double %cc_dep1) {
+; CHECK-LABEL: double_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    lgdr %r0, %f0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    ldgr %f0, %r0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call double asm sideeffect "", "=r,0"(double %cc_dep1)
+  ret double %0
+}
+
+define void @longdouble_and_r(ptr noalias nocapture writeonly sret(fp128) align 8 %agg.result, ptr %0) {
+; CHECK-LABEL: longdouble_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    lg %r1, 8(%r3)
+; CHECK-NEXT:    lg %r0, 0(%r3)
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    stg %r1, 8(%r2)
+; CHECK-NEXT:    stg %r0, 0(%r2)
+; CHECK-NEXT:    br %r14
+entry:
+  %cc_dep1 = load fp128, ptr %0, align 8
+  %1 = tail call fp128 asm sideeffect "", "=r,0"(fp128 %cc_dep1)
+  store fp128 %1, ptr %agg.result, align 8
+  ret void
+}
+
+define float @float_and_v(float %cc_dep1) {
+; CHECK-LABEL: float_and_v:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call float asm sideeffect "", "=v,0"(float %cc_dep1)
+  ret float %0
+}
+
+define double @double_and_v(double %cc_dep1) {
+; CHECK-LABEL: double_and_v:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call double asm sideeffect "", "=v,0"(double %cc_dep1)
+  ret double %0
+}
+
+define void @longdouble_and_v(ptr noalias nocapture writeonly sret(fp128) align 8 %agg.result, ptr %0) {
+; CHECK-LABEL: longdouble_and_v:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vl %v0, 0(%r3), 3
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vst %v0, 0(%r2), 3
+; CHECK-NEXT:    br %r14
+entry:
+  %cc_dep1 = load fp128, ptr %0, align 8
+  %1 = tail call fp128 asm sideeffect "", "=v,0"(fp128 %cc_dep1)
+  store fp128 %1, ptr %agg.result, align 8
+  ret void
+}
+
+define <2 x i16> @vec32_and_r(<2 x i16> %cc_dep1) {
+; CHECK-LABEL: vec32_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlgvf %r0, %v24, 0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlvgf %v24, %r0, 0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i16> asm sideeffect "", "=r,0"(<2 x i16> %cc_dep1)
+  ret <2 x i16> %0
+}
+
+define <2 x i32> @vec64_and_r(<2 x i32> %cc_dep1) {
+; CHECK-LABEL: vec64_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlgvg %r0, %v24, 0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlvgg %v24, %r0, 0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i32> asm sideeffect "", "=r,0"(<2 x i32> %cc_dep1)
+  ret <2 x i32> %0
+}
+
+define <4 x i32> @vec128_and_r(<4 x i32> %cc_dep1) {
+; CHECK-LABEL: vec128_and_r:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlgvg %r1, %v24, 1
+; CHECK-NEXT:    vlgvg %r0, %v24, 0
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlvgp %v24, %r0, %r1
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <4 x i32> asm sideeffect "", "=r,0"(<4 x i32> %cc_dep1)
+  ret <4 x i32> %0
+}
+
+define <2 x i16> @vec32_and_f(<2 x i16> %cc_dep1) {
+; CHECK-LABEL: vec32_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlr %v0, %v24
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlr %v24, %v0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i16> asm sideeffect "", "=f,0"(<2 x i16> %cc_dep1)
+  ret <2 x i16> %0
+}
+
+define <2 x i32> @vec64_and_f(<2 x i32> %cc_dep1) {
+; CHECK-LABEL: vec64_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vlr %v0, %v24
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vlr %v24, %v0
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <2 x i32> asm sideeffect "", "=f,0"(<2 x i32> %cc_dep1)
+  ret <2 x i32> %0
+}
+
+define <4 x i32> @vec128_and_f(<4 x i32> %cc_dep1) {
+; CHECK-LABEL: vec128_and_f:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vrepg %v2, %v24, 1
+; CHECK-NEXT:    vlr %v0, %v24
+; CHECK-NEXT:    #APP
+; CHECK-NEXT:    #NO_APP
+; CHECK-NEXT:    vmrhg %v24, %v0, %v2
+; CHECK-NEXT:    br %r14
+entry:
+  %0 = tail call <4 x i32> asm sideeffect "", "=f,0"(<4 x i32> %cc_dep1)
+  ret <4 x i32> %0
+}
+

diff  --git a/llvm/test/CodeGen/SystemZ/inline-asm-v-constraint-novecfacility.ll b/llvm/test/CodeGen/SystemZ/inline-asm-v-constraint-novecfacility.ll
new file mode 100644
index 000000000000..449be18281cc
--- /dev/null
+++ b/llvm/test/CodeGen/SystemZ/inline-asm-v-constraint-novecfacility.ll
@@ -0,0 +1,9 @@
+; RUN: not llc < %s -mtriple=s390x-linux-gnu -mcpu=zEC12 2>&1 | FileCheck %s
+
+; CHECK: error: couldn't allocate output register for constraint 'v'
+
+define signext i32 @int_and_v(i32 signext %cc_dep1) {
+entry:
+  %0 = tail call i32 asm sideeffect "", "=v,0"(i32 %cc_dep1)
+  ret i32 %0
+}


        


More information about the llvm-commits mailing list