Skip to content

Commit

Permalink
[SystemZ][FPEnv] Back-end support for STRICT_[SU]INT_TO_FP
Browse files Browse the repository at this point in the history
As of b1d8576 there is middle-end support for STRICT_[SU]INT_TO_FP,
so this patch adds SystemZ back-end support as well.

The patch is SystemZ target specific except for adding SD patterns
strict_[su]int_to_fp and any_[su]int_to_fp to TargetSelectionDAG.td
as usual.
  • Loading branch information
uweigand committed Dec 17, 2019
1 parent 520e3d6 commit d1c0f14
Show file tree
Hide file tree
Showing 12 changed files with 462 additions and 21 deletions.
10 changes: 10 additions & 0 deletions llvm/include/llvm/Target/TargetSelectionDAG.td
Expand Up @@ -538,6 +538,10 @@ def strict_fp_to_sint : SDNode<"ISD::STRICT_FP_TO_SINT",
SDTFPToIntOp, [SDNPHasChain]>;
def strict_fp_to_uint : SDNode<"ISD::STRICT_FP_TO_UINT",
SDTFPToIntOp, [SDNPHasChain]>;
def strict_sint_to_fp : SDNode<"ISD::STRICT_SINT_TO_FP",
SDTIntToFPOp, [SDNPHasChain]>;
def strict_uint_to_fp : SDNode<"ISD::STRICT_UINT_TO_FP",
SDTIntToFPOp, [SDNPHasChain]>;

def setcc : SDNode<"ISD::SETCC" , SDTSetCC>;
def select : SDNode<"ISD::SELECT" , SDTSelect>;
Expand Down Expand Up @@ -1398,6 +1402,12 @@ def any_fp_to_sint : PatFrags<(ops node:$src),
def any_fp_to_uint : PatFrags<(ops node:$src),
[(strict_fp_to_uint node:$src),
(fp_to_uint node:$src)]>;
def any_sint_to_fp : PatFrags<(ops node:$src),
[(strict_sint_to_fp node:$src),
(sint_to_fp node:$src)]>;
def any_uint_to_fp : PatFrags<(ops node:$src),
[(strict_uint_to_fp node:$src),
(uint_to_fp node:$src)]>;

multiclass binary_atomic_op_ord<SDNode atomic_op> {
def #NAME#_monotonic : PatFrag<(ops node:$ptr, node:$val),
Expand Down
15 changes: 15 additions & 0 deletions llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
Expand Up @@ -219,6 +219,11 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::STRICT_FP_TO_SINT, VT, Legal);
if (Subtarget.hasFPExtension())
setOperationAction(ISD::STRICT_FP_TO_UINT, VT, Legal);

// And similarly for STRICT_[SU]INT_TO_FP.
setOperationAction(ISD::STRICT_SINT_TO_FP, VT, Legal);
if (Subtarget.hasFPExtension())
setOperationAction(ISD::STRICT_UINT_TO_FP, VT, Legal);
}
}

Expand Down Expand Up @@ -258,6 +263,8 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
if (!Subtarget.hasFPExtension()) {
setOperationAction(ISD::UINT_TO_FP, MVT::i32, Promote);
setOperationAction(ISD::UINT_TO_FP, MVT::i64, Expand);
setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i32, Promote);
setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::i64, Expand);
}

// We have native support for a 64-bit CTLZ, via FLOGR.
Expand Down Expand Up @@ -402,6 +409,10 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::v2f64, Legal);
setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::v2i64, Legal);
setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::v2f64, Legal);
setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::v2i64, Legal);
setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::v2f64, Legal);
setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::v2i64, Legal);
setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::v2f64, Legal);
}

if (Subtarget.hasVectorEnhancements2()) {
Expand All @@ -418,6 +429,10 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::STRICT_FP_TO_SINT, MVT::v4f32, Legal);
setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::v4i32, Legal);
setOperationAction(ISD::STRICT_FP_TO_UINT, MVT::v4f32, Legal);
setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::v4i32, Legal);
setOperationAction(ISD::STRICT_SINT_TO_FP, MVT::v4f32, Legal);
setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::v4i32, Legal);
setOperationAction(ISD::STRICT_UINT_TO_FP, MVT::v4f32, Legal);
}

// Handle floating-point types.
Expand Down
24 changes: 12 additions & 12 deletions llvm/lib/Target/SystemZ/SystemZInstrFP.td
Expand Up @@ -221,13 +221,13 @@ let Predicates = [FeatureNoVectorEnhancements1] in {

// Convert a signed integer register value to a floating-point one.
let Uses = [FPC], mayRaiseFPException = 1 in {
def CEFBR : UnaryRRE<"cefbr", 0xB394, sint_to_fp, FP32, GR32>;
def CDFBR : UnaryRRE<"cdfbr", 0xB395, sint_to_fp, FP64, GR32>;
def CXFBR : UnaryRRE<"cxfbr", 0xB396, sint_to_fp, FP128, GR32>;
def CEFBR : UnaryRRE<"cefbr", 0xB394, any_sint_to_fp, FP32, GR32>;
def CDFBR : UnaryRRE<"cdfbr", 0xB395, any_sint_to_fp, FP64, GR32>;
def CXFBR : UnaryRRE<"cxfbr", 0xB396, any_sint_to_fp, FP128, GR32>;

def CEGBR : UnaryRRE<"cegbr", 0xB3A4, sint_to_fp, FP32, GR64>;
def CDGBR : UnaryRRE<"cdgbr", 0xB3A5, sint_to_fp, FP64, GR64>;
def CXGBR : UnaryRRE<"cxgbr", 0xB3A6, sint_to_fp, FP128, GR64>;
def CEGBR : UnaryRRE<"cegbr", 0xB3A4, any_sint_to_fp, FP32, GR64>;
def CDGBR : UnaryRRE<"cdgbr", 0xB3A5, any_sint_to_fp, FP64, GR64>;
def CXGBR : UnaryRRE<"cxgbr", 0xB3A6, any_sint_to_fp, FP128, GR64>;
}

// The FP extension feature provides versions of the above that allow
Expand All @@ -254,13 +254,13 @@ let Predicates = [FeatureFPExtension] in {
def CXLGBR : TernaryRRFe<"cxlgbr", 0xB3A2, FP128, GR64>;
}

def : Pat<(f32 (uint_to_fp GR32:$src)), (CELFBR 0, GR32:$src, 0)>;
def : Pat<(f64 (uint_to_fp GR32:$src)), (CDLFBR 0, GR32:$src, 0)>;
def : Pat<(f128 (uint_to_fp GR32:$src)), (CXLFBR 0, GR32:$src, 0)>;
def : Pat<(f32 (any_uint_to_fp GR32:$src)), (CELFBR 0, GR32:$src, 0)>;
def : Pat<(f64 (any_uint_to_fp GR32:$src)), (CDLFBR 0, GR32:$src, 0)>;
def : Pat<(f128 (any_uint_to_fp GR32:$src)), (CXLFBR 0, GR32:$src, 0)>;

def : Pat<(f32 (uint_to_fp GR64:$src)), (CELGBR 0, GR64:$src, 0)>;
def : Pat<(f64 (uint_to_fp GR64:$src)), (CDLGBR 0, GR64:$src, 0)>;
def : Pat<(f128 (uint_to_fp GR64:$src)), (CXLGBR 0, GR64:$src, 0)>;
def : Pat<(f32 (any_uint_to_fp GR64:$src)), (CELGBR 0, GR64:$src, 0)>;
def : Pat<(f64 (any_uint_to_fp GR64:$src)), (CDLGBR 0, GR64:$src, 0)>;
def : Pat<(f128 (any_uint_to_fp GR64:$src)), (CXLGBR 0, GR64:$src, 0)>;
}

// Convert a floating-point register value to a signed integer value,
Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/Target/SystemZ/SystemZInstrVector.td
Expand Up @@ -1034,15 +1034,15 @@ let Predicates = [FeatureVector] in {
def VCDGB : TernaryVRRa<"vcdgb", 0xE7C3, null_frag, v128db, v128g, 3, 0>;
def WCDGB : TernaryVRRa<"wcdgb", 0xE7C3, null_frag, v64db, v64g, 3, 8>;
}
def : FPConversion<VCDGB, sint_to_fp, v128db, v128g, 0, 0>;
def : FPConversion<VCDGB, any_sint_to_fp, v128db, v128g, 0, 0>;
let Predicates = [FeatureVectorEnhancements2] in {
let Uses = [FPC], mayRaiseFPException = 1 in {
let isAsmParserOnly = 1 in
def VCFPS : TernaryVRRaFloatGeneric<"vcfps", 0xE7C3>;
def VCEFB : TernaryVRRa<"vcefb", 0xE7C3, null_frag, v128sb, v128g, 2, 0>;
def WCEFB : TernaryVRRa<"wcefb", 0xE7C3, null_frag, v32sb, v32f, 2, 8>;
}
def : FPConversion<VCEFB, sint_to_fp, v128sb, v128f, 0, 0>;
def : FPConversion<VCEFB, any_sint_to_fp, v128sb, v128f, 0, 0>;
}

// Convert from logical.
Expand All @@ -1051,15 +1051,15 @@ let Predicates = [FeatureVector] in {
def VCDLGB : TernaryVRRa<"vcdlgb", 0xE7C1, null_frag, v128db, v128g, 3, 0>;
def WCDLGB : TernaryVRRa<"wcdlgb", 0xE7C1, null_frag, v64db, v64g, 3, 8>;
}
def : FPConversion<VCDLGB, uint_to_fp, v128db, v128g, 0, 0>;
def : FPConversion<VCDLGB, any_uint_to_fp, v128db, v128g, 0, 0>;
let Predicates = [FeatureVectorEnhancements2] in {
let Uses = [FPC], mayRaiseFPException = 1 in {
let isAsmParserOnly = 1 in
def VCFPL : TernaryVRRaFloatGeneric<"vcfpl", 0xE7C1>;
def VCELFB : TernaryVRRa<"vcelfb", 0xE7C1, null_frag, v128sb, v128g, 2, 0>;
def WCELFB : TernaryVRRa<"wcelfb", 0xE7C1, null_frag, v32sb, v32f, 2, 8>;
}
def : FPConversion<VCELFB, uint_to_fp, v128sb, v128f, 0, 0>;
def : FPConversion<VCELFB, any_uint_to_fp, v128sb, v128f, 0, 0>;
}

// Convert to fixed.
Expand Down
45 changes: 45 additions & 0 deletions llvm/test/CodeGen/SystemZ/fp-strict-conv-05.ll
@@ -0,0 +1,45 @@
; Test strict conversions of signed i32s to floating-point values.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s

declare float @llvm.experimental.constrained.sitofp.f32.i32(i32, metadata, metadata)
declare double @llvm.experimental.constrained.sitofp.f64.i32(i32, metadata, metadata)
declare fp128 @llvm.experimental.constrained.sitofp.f128.i32(i32, metadata, metadata)

; Check i32->f32.
define float @f1(i32 %i) #0 {
; CHECK-LABEL: f1:
; CHECK: cefbr %f0, %r2
; CHECK: br %r14
%conv = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %i,
metadata !"round.dynamic",
metadata !"fpexcept.strict") #0
ret float %conv
}

; Check i32->f64.
define double @f2(i32 %i) #0 {
; CHECK-LABEL: f2:
; CHECK: cdfbr %f0, %r2
; CHECK: br %r14
%conv = call double @llvm.experimental.constrained.sitofp.f64.i32(i32 %i,
metadata !"round.dynamic",
metadata !"fpexcept.strict") #0
ret double %conv
}

; Check i32->f128.
define void @f3(i32 %i, fp128 *%dst) #0 {
; CHECK-LABEL: f3:
; CHECK: cxfbr %f0, %r2
; CHECK: std %f0, 0(%r3)
; CHECK: std %f2, 8(%r3)
; CHECK: br %r14
%conv = call fp128 @llvm.experimental.constrained.sitofp.f128.i32(i32 %i,
metadata !"round.dynamic",
metadata !"fpexcept.strict") #0
store fp128 %conv, fp128 *%dst
ret void
}

attributes #0 = { strictfp }
49 changes: 49 additions & 0 deletions llvm/test/CodeGen/SystemZ/fp-strict-conv-06.ll
@@ -0,0 +1,49 @@
; Test strict conversions of unsigned i32s to floating-point values (z10 only).
;
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | FileCheck %s

declare float @llvm.experimental.constrained.uitofp.f32.i32(i32, metadata, metadata)
declare double @llvm.experimental.constrained.uitofp.f64.i32(i32, metadata, metadata)
declare fp128 @llvm.experimental.constrained.uitofp.f128.i32(i32, metadata, metadata)

; Check i32->f32. There is no native instruction, so we must promote
; to i64 first.
define float @f1(i32 %i) #0 {
; CHECK-LABEL: f1:
; CHECK: llgfr [[REGISTER:%r[0-5]]], %r2
; CHECK: cegbr %f0, [[REGISTER]]
; CHECK: br %r14
%conv = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %i,
metadata !"round.dynamic",
metadata !"fpexcept.strict") #0
ret float %conv
}

; Check i32->f64.
define double @f2(i32 %i) #0 {
; CHECK-LABEL: f2:
; CHECK: llgfr [[REGISTER:%r[0-5]]], %r2
; CHECK: cdgbr %f0, [[REGISTER]]
; CHECK: br %r14
%conv = call double @llvm.experimental.constrained.uitofp.f64.i32(i32 %i,
metadata !"round.dynamic",
metadata !"fpexcept.strict") #0
ret double %conv
}

; Check i32->f128.
define void @f3(i32 %i, fp128 *%dst) #0 {
; CHECK-LABEL: f3:
; CHECK: llgfr [[REGISTER:%r[0-5]]], %r2
; CHECK: cxgbr %f0, [[REGISTER]]
; CHECK: std %f0, 0(%r3)
; CHECK: std %f2, 8(%r3)
; CHECK: br %r14
%conv = call fp128 @llvm.experimental.constrained.uitofp.f128.i32(i32 %i,
metadata !"round.dynamic",
metadata !"fpexcept.strict") #0
store fp128 %conv, fp128 *%dst
ret void
}

attributes #0 = { strictfp }
45 changes: 45 additions & 0 deletions llvm/test/CodeGen/SystemZ/fp-strict-conv-07.ll
@@ -0,0 +1,45 @@
; Test strict conversions of signed i64s to floating-point values.
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s

declare float @llvm.experimental.constrained.sitofp.f32.i64(i64, metadata, metadata)
declare double @llvm.experimental.constrained.sitofp.f64.i64(i64, metadata, metadata)
declare fp128 @llvm.experimental.constrained.sitofp.f128.i64(i64, metadata, metadata)

; Test i64->f32.
define float @f1(i64 %i) #0 {
; CHECK-LABEL: f1:
; CHECK: cegbr %f0, %r2
; CHECK: br %r14
%conv = call float @llvm.experimental.constrained.sitofp.f32.i64(i64 %i,
metadata !"round.dynamic",
metadata !"fpexcept.strict") #0
ret float %conv
}

; Test i64->f64.
define double @f2(i64 %i) #0 {
; CHECK-LABEL: f2:
; CHECK: cdgbr %f0, %r2
; CHECK: br %r14
%conv = call double @llvm.experimental.constrained.sitofp.f64.i64(i64 %i,
metadata !"round.dynamic",
metadata !"fpexcept.strict") #0
ret double %conv
}

; Test i64->f128.
define void @f3(i64 %i, fp128 *%dst) #0 {
; CHECK-LABEL: f3:
; CHECK: cxgbr %f0, %r2
; CHECK: std %f0, 0(%r3)
; CHECK: std %f2, 8(%r3)
; CHECK: br %r14
%conv = call fp128 @llvm.experimental.constrained.sitofp.f128.i64(i64 %i,
metadata !"round.dynamic",
metadata !"fpexcept.strict") #0
store fp128 %conv, fp128 *%dst
ret void
}

attributes #0 = { strictfp }
47 changes: 47 additions & 0 deletions llvm/test/CodeGen/SystemZ/fp-strict-conv-08.ll
@@ -0,0 +1,47 @@
; Test strict conversions of unsigned i64s to floating-point values (z10 only).
;
; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | FileCheck %s

declare float @llvm.experimental.constrained.uitofp.f32.i64(i64, metadata, metadata)
declare double @llvm.experimental.constrained.uitofp.f64.i64(i64, metadata, metadata)
declare fp128 @llvm.experimental.constrained.uitofp.f128.i64(i64, metadata, metadata)

; Test i64->f32. There's no native support for unsigned i64-to-fp conversions,
; but we should be able to implement them using signed i64-to-fp conversions.
define float @f1(i64 %i) #0 {
; CHECK-LABEL: f1:
; CHECK: cegbr
; CHECK: aebr
; CHECK: br %r14
%conv = call float @llvm.experimental.constrained.uitofp.f32.i64(i64 %i,
metadata !"round.dynamic",
metadata !"fpexcept.strict") #0
ret float %conv
}

; Test i64->f64.
define double @f2(i64 %i) #0 {
; CHECK-LABEL: f2:
; CHECK: ldgr
; CHECK: adbr
; CHECK: br %r14
%conv = call double @llvm.experimental.constrained.uitofp.f64.i64(i64 %i,
metadata !"round.dynamic",
metadata !"fpexcept.strict") #0
ret double %conv
}

; Test i64->f128.
define void @f3(i64 %i, fp128 *%dst) #0 {
; CHECK-LABEL: f3:
; CHECK: cxgbr
; CHECK: axbr
; CHECK: br %r14
%conv = call fp128 @llvm.experimental.constrained.uitofp.f128.i64(i64 %i,
metadata !"round.dynamic",
metadata !"fpexcept.strict") #0
store fp128 %conv, fp128 *%dst
ret void
}

attributes #0 = { strictfp }

0 comments on commit d1c0f14

Please sign in to comment.