1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-02-01 13:11:39 +01:00

[AArch64] Do not promote f16 when subtarget HasFullFP16

Armv8.2-A adds FP16 support, i.e. f16 is not only a storage-only type, but it
also supports performing data processing on 16-bit floating-point quantities.
All the necessary (tablegen) groundwork of adding the ARMv8.2-A FP16 (scalar)
instructions was done in D15014. To take advantage of this, this patch avoids
promotion of f16 to f32 types when the subtarget supports FullFP16, which
enables instruction selection of these FP16 instructions.

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

llvm-svn: 311154
This commit is contained in:
Sjoerd Meijer 2017-08-18 10:51:14 +00:00
parent 3797af285e
commit 75c6d8cc25
3 changed files with 880 additions and 490 deletions

View File

@ -166,6 +166,7 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
setOperationAction(ISD::GlobalTLSAddress, MVT::i64, Custom);
setOperationAction(ISD::SETCC, MVT::i32, Custom);
setOperationAction(ISD::SETCC, MVT::i64, Custom);
setOperationAction(ISD::SETCC, MVT::f16, Custom);
setOperationAction(ISD::SETCC, MVT::f32, Custom);
setOperationAction(ISD::SETCC, MVT::f64, Custom);
setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
@ -173,14 +174,17 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
setOperationAction(ISD::BR_CC, MVT::i64, Custom);
setOperationAction(ISD::BR_CC, MVT::f16, Custom);
setOperationAction(ISD::BR_CC, MVT::f32, Custom);
setOperationAction(ISD::BR_CC, MVT::f64, Custom);
setOperationAction(ISD::SELECT, MVT::i32, Custom);
setOperationAction(ISD::SELECT, MVT::i64, Custom);
setOperationAction(ISD::SELECT, MVT::f16, Custom);
setOperationAction(ISD::SELECT, MVT::f32, Custom);
setOperationAction(ISD::SELECT, MVT::f64, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i64, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f16, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f64, Custom);
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
@ -318,41 +322,45 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FCOPYSIGN, MVT::f64, Custom);
setOperationAction(ISD::FCOPYSIGN, MVT::f32, Custom);
// f16 is a storage-only type, always promote it to f32.
setOperationAction(ISD::SETCC, MVT::f16, Promote);
setOperationAction(ISD::BR_CC, MVT::f16, Promote);
setOperationAction(ISD::SELECT_CC, MVT::f16, Promote);
setOperationAction(ISD::SELECT, MVT::f16, Promote);
setOperationAction(ISD::FADD, MVT::f16, Promote);
setOperationAction(ISD::FSUB, MVT::f16, Promote);
setOperationAction(ISD::FMUL, MVT::f16, Promote);
setOperationAction(ISD::FDIV, MVT::f16, Promote);
setOperationAction(ISD::FREM, MVT::f16, Promote);
setOperationAction(ISD::FMA, MVT::f16, Promote);
setOperationAction(ISD::FNEG, MVT::f16, Promote);
setOperationAction(ISD::FABS, MVT::f16, Promote);
setOperationAction(ISD::FCEIL, MVT::f16, Promote);
setOperationAction(ISD::FCOPYSIGN, MVT::f16, Promote);
setOperationAction(ISD::FCOS, MVT::f16, Promote);
setOperationAction(ISD::FFLOOR, MVT::f16, Promote);
setOperationAction(ISD::FNEARBYINT, MVT::f16, Promote);
setOperationAction(ISD::FPOW, MVT::f16, Promote);
setOperationAction(ISD::FPOWI, MVT::f16, Promote);
setOperationAction(ISD::FRINT, MVT::f16, Promote);
setOperationAction(ISD::FCOS, MVT::f16, Promote);
setOperationAction(ISD::FSIN, MVT::f16, Promote);
setOperationAction(ISD::FSINCOS, MVT::f16, Promote);
setOperationAction(ISD::FSQRT, MVT::f16, Promote);
setOperationAction(ISD::FEXP, MVT::f16, Promote);
setOperationAction(ISD::FEXP2, MVT::f16, Promote);
setOperationAction(ISD::FLOG, MVT::f16, Promote);
setOperationAction(ISD::FLOG2, MVT::f16, Promote);
setOperationAction(ISD::FLOG10, MVT::f16, Promote);
setOperationAction(ISD::FROUND, MVT::f16, Promote);
setOperationAction(ISD::FTRUNC, MVT::f16, Promote);
setOperationAction(ISD::FMINNUM, MVT::f16, Promote);
setOperationAction(ISD::FMAXNUM, MVT::f16, Promote);
setOperationAction(ISD::FMINNAN, MVT::f16, Promote);
setOperationAction(ISD::FMAXNAN, MVT::f16, Promote);
setOperationAction(ISD::FCOPYSIGN, MVT::f16, Promote);
if (!Subtarget->hasFullFP16()) {
setOperationAction(ISD::SELECT, MVT::f16, Promote);
setOperationAction(ISD::SELECT_CC, MVT::f16, Promote);
setOperationAction(ISD::SETCC, MVT::f16, Promote);
setOperationAction(ISD::BR_CC, MVT::f16, Promote);
setOperationAction(ISD::FADD, MVT::f16, Promote);
setOperationAction(ISD::FSUB, MVT::f16, Promote);
setOperationAction(ISD::FMUL, MVT::f16, Promote);
setOperationAction(ISD::FDIV, MVT::f16, Promote);
setOperationAction(ISD::FREM, MVT::f16, Promote);
setOperationAction(ISD::FMA, MVT::f16, Promote);
setOperationAction(ISD::FNEG, MVT::f16, Promote);
setOperationAction(ISD::FABS, MVT::f16, Promote);
setOperationAction(ISD::FCEIL, MVT::f16, Promote);
setOperationAction(ISD::FSQRT, MVT::f16, Promote);
setOperationAction(ISD::FCOS, MVT::f16, Promote);
setOperationAction(ISD::FFLOOR, MVT::f16, Promote);
setOperationAction(ISD::FNEARBYINT, MVT::f16, Promote);
setOperationAction(ISD::FRINT, MVT::f16, Promote);
setOperationAction(ISD::FROUND, MVT::f16, Promote);
setOperationAction(ISD::FTRUNC, MVT::f16, Promote);
setOperationAction(ISD::FMINNUM, MVT::f16, Promote);
setOperationAction(ISD::FMAXNUM, MVT::f16, Promote);
setOperationAction(ISD::FMINNAN, MVT::f16, Promote);
setOperationAction(ISD::FMAXNAN, MVT::f16, Promote);
}
// v4f16 is also a storage-only type, so promote it to v4f32 when that is
// known to be safe.
@ -445,6 +453,19 @@ AArch64TargetLowering::AArch64TargetLowering(const TargetMachine &TM,
setOperationAction(ISD::FMAXNAN, Ty, Legal);
}
if (Subtarget->hasFullFP16()) {
setOperationAction(ISD::FNEARBYINT, MVT::f16, Legal);
setOperationAction(ISD::FFLOOR, MVT::f16, Legal);
setOperationAction(ISD::FCEIL, MVT::f16, Legal);
setOperationAction(ISD::FRINT, MVT::f16, Legal);
setOperationAction(ISD::FTRUNC, MVT::f16, Legal);
setOperationAction(ISD::FROUND, MVT::f16, Legal);
setOperationAction(ISD::FMINNUM, MVT::f16, Legal);
setOperationAction(ISD::FMAXNUM, MVT::f16, Legal);
setOperationAction(ISD::FMINNAN, MVT::f16, Legal);
setOperationAction(ISD::FMAXNAN, MVT::f16, Legal);
}
setOperationAction(ISD::PREFETCH, MVT::Other, Custom);
setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i128, Custom);
@ -775,8 +796,9 @@ void AArch64TargetLowering::addTypeForNEON(MVT VT, MVT PromotedBitwiseVT) {
for (unsigned Opcode : {ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX})
setOperationAction(Opcode, VT, Legal);
// F[MIN|MAX][NUM|NAN] are available for all FP NEON types (not f16 though!).
if (VT.isFloatingPoint() && VT.getVectorElementType() != MVT::f16)
// F[MIN|MAX][NUM|NAN] are available for all FP NEON types.
if (VT.isFloatingPoint() &&
(VT.getVectorElementType() != MVT::f16 || Subtarget->hasFullFP16()))
for (unsigned Opcode : {ISD::FMINNAN, ISD::FMAXNAN,
ISD::FMINNUM, ISD::FMAXNUM})
setOperationAction(Opcode, VT, Legal);
@ -1418,12 +1440,13 @@ static bool isLegalArithImmed(uint64_t C) {
}
static SDValue emitComparison(SDValue LHS, SDValue RHS, ISD::CondCode CC,
const SDLoc &dl, SelectionDAG &DAG) {
const SDLoc &dl, SelectionDAG &DAG,
bool FullFP16 = false) {
EVT VT = LHS.getValueType();
if (VT.isFloatingPoint()) {
assert(VT != MVT::f128);
if (VT == MVT::f16) {
if (VT == MVT::f16 && !FullFP16) {
LHS = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f32, LHS);
RHS = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f32, RHS);
VT = MVT::f32;
@ -1511,11 +1534,12 @@ static SDValue emitConditionalComparison(SDValue LHS, SDValue RHS,
ISD::CondCode CC, SDValue CCOp,
AArch64CC::CondCode Predicate,
AArch64CC::CondCode OutCC,
const SDLoc &DL, SelectionDAG &DAG) {
const SDLoc &DL, SelectionDAG &DAG,
bool FullFP16 = false) {
unsigned Opcode = 0;
if (LHS.getValueType().isFloatingPoint()) {
assert(LHS.getValueType() != MVT::f128);
if (LHS.getValueType() == MVT::f16) {
if (LHS.getValueType() == MVT::f16 && !FullFP16) {
LHS = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, LHS);
RHS = DAG.getNode(ISD::FP_EXTEND, DL, MVT::f32, RHS);
}
@ -1604,7 +1628,7 @@ static bool isConjunctionDisjunctionTree(const SDValue Val, bool &CanNegate,
/// depth to avoid stack overflow.
static SDValue emitConjunctionDisjunctionTreeRec(SelectionDAG &DAG, SDValue Val,
AArch64CC::CondCode &OutCC, bool Negate, SDValue CCOp,
AArch64CC::CondCode Predicate) {
AArch64CC::CondCode Predicate, bool FullFP16 = false) {
// We're at a tree leaf, produce a conditional comparison operation.
unsigned Opcode = Val->getOpcode();
if (Opcode == ISD::SETCC) {
@ -1630,7 +1654,8 @@ static SDValue emitConjunctionDisjunctionTreeRec(SelectionDAG &DAG, SDValue Val,
ExtraCmp = emitComparison(LHS, RHS, CC, DL, DAG);
else
ExtraCmp = emitConditionalComparison(LHS, RHS, CC, CCOp, Predicate,
ExtraCC, DL, DAG);
ExtraCC, DL, DAG,
FullFP16);
CCOp = ExtraCmp;
Predicate = ExtraCC;
}
@ -1641,7 +1666,7 @@ static SDValue emitConjunctionDisjunctionTreeRec(SelectionDAG &DAG, SDValue Val,
return emitComparison(LHS, RHS, CC, DL, DAG);
// Otherwise produce a ccmp.
return emitConditionalComparison(LHS, RHS, CC, CCOp, Predicate, OutCC, DL,
DAG);
DAG, FullFP16);
}
assert((Opcode == ISD::AND || (Opcode == ISD::OR && Val->hasOneUse())) &&
"Valid conjunction/disjunction tree");
@ -1688,13 +1713,13 @@ static SDValue emitConjunctionDisjunctionTreeRec(SelectionDAG &DAG, SDValue Val,
// the "flags to test" afterwards.
AArch64CC::CondCode RHSCC;
SDValue CmpR = emitConjunctionDisjunctionTreeRec(DAG, RHS, RHSCC, Negate,
CCOp, Predicate);
CCOp, Predicate, FullFP16);
if (NegateOpsAndResult && !Negate)
RHSCC = AArch64CC::getInvertedCondCode(RHSCC);
// Emit LHS. We may need to negate it.
SDValue CmpL = emitConjunctionDisjunctionTreeRec(DAG, LHS, OutCC,
NegateOpsAndResult, CmpR,
RHSCC);
RHSCC, FullFP16);
// If we transformed an OR to and AND then we have to negate the result
// (or absorb the Negate parameter).
if (NegateOpsAndResult && !Negate)
@ -1706,20 +1731,21 @@ static SDValue emitConjunctionDisjunctionTreeRec(SelectionDAG &DAG, SDValue Val,
/// of CCMP/CFCMP ops. See @ref AArch64CCMP.
/// \see emitConjunctionDisjunctionTreeRec().
static SDValue emitConjunctionDisjunctionTree(SelectionDAG &DAG, SDValue Val,
AArch64CC::CondCode &OutCC) {
AArch64CC::CondCode &OutCC,
bool FullFP16 = false) {
bool CanNegate;
if (!isConjunctionDisjunctionTree(Val, CanNegate))
return SDValue();
return emitConjunctionDisjunctionTreeRec(DAG, Val, OutCC, false, SDValue(),
AArch64CC::AL);
AArch64CC::AL, FullFP16);
}
/// @}
static SDValue getAArch64Cmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
SDValue &AArch64cc, SelectionDAG &DAG,
const SDLoc &dl) {
const SDLoc &dl, bool FullFP16 = false) {
if (ConstantSDNode *RHSC = dyn_cast<ConstantSDNode>(RHS.getNode())) {
EVT VT = RHS.getValueType();
uint64_t C = RHSC->getZExtValue();
@ -1806,13 +1832,13 @@ static SDValue getAArch64Cmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
DAG.getValueType(MVT::i16));
Cmp = emitComparison(SExt, DAG.getConstant(ValueofRHS, dl,
RHS.getValueType()),
CC, dl, DAG);
CC, dl, DAG, FullFP16);
AArch64CC = changeIntCCToAArch64CC(CC);
}
}
if (!Cmp && (RHSC->isNullValue() || RHSC->isOne())) {
if ((Cmp = emitConjunctionDisjunctionTree(DAG, LHS, AArch64CC))) {
if ((Cmp = emitConjunctionDisjunctionTree(DAG, LHS, AArch64CC, FullFP16))) {
if ((CC == ISD::SETNE) ^ RHSC->isNullValue())
AArch64CC = AArch64CC::getInvertedCondCode(AArch64CC);
}
@ -1820,7 +1846,7 @@ static SDValue getAArch64Cmp(SDValue LHS, SDValue RHS, ISD::CondCode CC,
}
if (!Cmp) {
Cmp = emitComparison(LHS, RHS, CC, dl, DAG);
Cmp = emitComparison(LHS, RHS, CC, dl, DAG, FullFP16);
AArch64CC = changeIntCCToAArch64CC(CC);
}
AArch64cc = DAG.getConstant(AArch64CC, dl, MVT_CC);
@ -2171,8 +2197,9 @@ SDValue AArch64TargetLowering::LowerFP_TO_INT(SDValue Op,
if (Op.getOperand(0).getValueType().isVector())
return LowerVectorFP_TO_INT(Op, DAG);
// f16 conversions are promoted to f32.
if (Op.getOperand(0).getValueType() == MVT::f16) {
// f16 conversions are promoted to f32 when full fp16 is not supported.
if (Op.getOperand(0).getValueType() == MVT::f16 &&
!Subtarget->hasFullFP16()) {
SDLoc dl(Op);
return DAG.getNode(
Op.getOpcode(), dl, Op.getValueType(),
@ -2227,8 +2254,9 @@ SDValue AArch64TargetLowering::LowerINT_TO_FP(SDValue Op,
if (Op.getValueType().isVector())
return LowerVectorINT_TO_FP(Op, DAG);
// f16 conversions are promoted to f32.
if (Op.getValueType() == MVT::f16) {
// f16 conversions are promoted to f32 when full fp16 is not supported.
if (Op.getValueType() == MVT::f16 &&
!Subtarget->hasFullFP16()) {
SDLoc dl(Op);
return DAG.getNode(
ISD::FP_ROUND, dl, MVT::f16,
@ -4012,16 +4040,18 @@ SDValue AArch64TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) const {
}
SDValue CCVal;
SDValue Cmp = getAArch64Cmp(LHS, RHS, CC, CCVal, DAG, dl);
SDValue Cmp = getAArch64Cmp(LHS, RHS, CC, CCVal, DAG, dl,
Subtarget->hasFullFP16());
return DAG.getNode(AArch64ISD::BRCOND, dl, MVT::Other, Chain, Dest, CCVal,
Cmp);
}
assert(LHS.getValueType() == MVT::f32 || LHS.getValueType() == MVT::f64);
assert(LHS.getValueType() == MVT::f16 || LHS.getValueType() == MVT::f32 ||
LHS.getValueType() == MVT::f64);
// Unfortunately, the mapping of LLVM FP CC's onto AArch64 CC's isn't totally
// clean. Some of them require two branches to implement.
SDValue Cmp = emitComparison(LHS, RHS, CC, dl, DAG);
SDValue Cmp = emitComparison(LHS, RHS, CC, dl, DAG, Subtarget->hasFullFP16());
AArch64CC::CondCode CC1, CC2;
changeFPCCToAArch64CC(CC, CC1, CC2);
SDValue CC1Val = DAG.getConstant(CC1, dl, MVT::i32);
@ -4176,7 +4206,8 @@ SDValue AArch64TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
if (LHS.getValueType().isInteger()) {
SDValue CCVal;
SDValue Cmp =
getAArch64Cmp(LHS, RHS, ISD::getSetCCInverse(CC, true), CCVal, DAG, dl);
getAArch64Cmp(LHS, RHS, ISD::getSetCCInverse(CC, true), CCVal, DAG, dl,
Subtarget->hasFullFP16());
// Note that we inverted the condition above, so we reverse the order of
// the true and false operands here. This will allow the setcc to be
@ -4185,11 +4216,12 @@ SDValue AArch64TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
}
// Now we know we're dealing with FP values.
assert(LHS.getValueType() == MVT::f32 || LHS.getValueType() == MVT::f64);
assert(LHS.getValueType() == MVT::f16 || LHS.getValueType() == MVT::f32 ||
LHS.getValueType() == MVT::f64);
// If that fails, we'll need to perform an FCMP + CSEL sequence. Go ahead
// and do the comparison.
SDValue Cmp = emitComparison(LHS, RHS, CC, dl, DAG);
SDValue Cmp = emitComparison(LHS, RHS, CC, dl, DAG, Subtarget->hasFullFP16());
AArch64CC::CondCode CC1, CC2;
changeFPCCToAArch64CC(CC, CC1, CC2);
@ -4235,7 +4267,7 @@ SDValue AArch64TargetLowering::LowerSELECT_CC(ISD::CondCode CC, SDValue LHS,
}
// Also handle f16, for which we need to do a f32 comparison.
if (LHS.getValueType() == MVT::f16) {
if (LHS.getValueType() == MVT::f16 && !Subtarget->hasFullFP16()) {
LHS = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f32, LHS);
RHS = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f32, RHS);
}
@ -4355,17 +4387,19 @@ SDValue AArch64TargetLowering::LowerSELECT_CC(ISD::CondCode CC, SDValue LHS,
}
SDValue CCVal;
SDValue Cmp = getAArch64Cmp(LHS, RHS, CC, CCVal, DAG, dl);
SDValue Cmp = getAArch64Cmp(LHS, RHS, CC, CCVal, DAG, dl,
Subtarget->hasFullFP16());
EVT VT = TVal.getValueType();
return DAG.getNode(Opcode, dl, VT, TVal, FVal, CCVal, Cmp);
}
// Now we know we're dealing with FP values.
assert(LHS.getValueType() == MVT::f32 || LHS.getValueType() == MVT::f64);
assert(LHS.getValueType() == MVT::f16 || LHS.getValueType() == MVT::f32 ||
LHS.getValueType() == MVT::f64);
assert(LHS.getValueType() == RHS.getValueType());
EVT VT = TVal.getValueType();
SDValue Cmp = emitComparison(LHS, RHS, CC, dl, DAG);
SDValue Cmp = emitComparison(LHS, RHS, CC, dl, DAG, Subtarget->hasFullFP16());
// Unfortunately, the mapping of LLVM FP CC's onto AArch64 CC's isn't totally
// clean. Some of them require two CSELs to implement.
@ -4863,6 +4897,8 @@ bool AArch64TargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT) const {
return AArch64_AM::getFP64Imm(Imm) != -1;
else if (VT == MVT::f32)
return AArch64_AM::getFP32Imm(Imm) != -1;
else if (VT == MVT::f16 && Subtarget->hasFullFP16())
return AArch64_AM::getFP16Imm(Imm) != -1;
return false;
}

View File

@ -0,0 +1,102 @@
; RUN: llc < %s -mtriple=aarch64-none-eabi -mattr=+fullfp16 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ILLEGAL
; RUN: llc < %s -mtriple=aarch64-none-eabi -mattr=-fullfp16 | FileCheck %s --check-prefix=CHECK-NOFP16 --check-prefix=CHECK-ILLEGAL
define half @Const0() {
entry:
ret half 0xH0000
}
; CHECK-ILLEGAL: .[[LBL0:LCPI0_[0-9]]]:
; CHECK-ILLEGAL-NEXT: .hword 0 // half 0
; CHECK-ILLEGAL-LABEL: Const0:
; CHECK-ILLEGAL: adrp x[[NUM:[0-9]+]], .[[LBL0]]
; CHECK-ILLEGAL-NEXT: ldr h0, [x[[NUM]], :lo12:.[[LBL0]]]
define half @Const1() {
entry:
ret half 0xH3C00
}
; CHECK-DAG-LABEL: Const1:
; CHECK-DAG-NEXT: fmov h0, #1.00000000
; CHECK-DAG-NEXT: ret
; CHECK-NOFP16: .[[LBL1:LCPI1_[0-9]]]:
; CHECK-NOFP16-NEXT: .hword 15360 // half 1
; CHECK-NOFP16-LABEL: Const1:
; CHECK-NOFP16: adrp x[[NUM:[0-9]+]], .[[LBL1]]
; CHECK-NOFP16-NEXT: ldr h0, [x[[NUM]], :lo12:.[[LBL1]]]
define half @Const2() {
entry:
ret half 0xH3000
}
; CHECK-DAG-LABEL: Const2:
; CHECK-DAG-NEXT: fmov h0, #0.12500000
; CHECK-DAG-NEXT: ret
; CHECK-NOFP16: .[[LBL2:LCPI2_[0-9]]]:
; CHECK-NOFP16-NEXT: .hword 12288 // half 0.125
; CHECK-NOFP16-LABEL: Const2:
; CHECK-NOFP16: adrp x[[NUM:[0-9]+]], .[[LBL2]]
; CHECK-NOFP16-NEXT: ldr h0, [x[[NUM]], :lo12:.[[LBL2]]]
define half @Const3() {
entry:
ret half 0xH4F80
}
; CHECK-DAG-LABEL: Const3:
; CHECK-DAG-NEXT: fmov h0, #30.00000000
; CHECK-DAG-NEXT: ret
; CHECK-NOFP16: .[[LBL3:LCPI3_[0-9]]]:
; CHECK-NOFP16-NEXT: .hword 20352 // half 30
; CHECK-NOFP16-LABEL: Const3:
; CHECK-NOFP16: adrp x[[NUM:[0-9]+]], .[[LBL3]]
; CHECK-NOFP16-NEXT: ldr h0, [x[[NUM]], :lo12:.[[LBL3]]]
define half @Const4() {
entry:
ret half 0xH4FC0
}
; CHECK-DAG-LABEL: Const4:
; CHECK-DAG-NEXT: fmov h0, #31.00000000
; CHECK-DAG-NEXT: ret
; CHECK-NOFP16: .[[LBL4:LCPI4_[0-9]]]:
; CHECK-NOFP16-NEXT: .hword 20416 // half 31
; CHECK-NOFP16-LABEL: Const4:
; CHECK-NOFP16: adrp x[[NUM:[0-9]+]], .[[LBL4]]
; CHECK-NOFP16-NEXT: ldr h0, [x[[NUM]], :lo12:.[[LBL4]]]
define half @Const5() {
entry:
ret half 0xH2FF0
}
; CHECK-ILLEGAL: .[[LBL5:LCPI5_[0-9]]]:
; CHECK-ILLEGAL-NEXT: .hword 12272 // half 0.12402
; CHECK-ILLEGAL-LABEL: Const5:
; CHECK-ILLEGAL: adrp x[[NUM:[0-9]+]], .[[LBL5]]
; CHECK-ILLEGAL-NEXT: ldr h0, [x[[NUM]], :lo12:.[[LBL5]]]
define half @Const6() {
entry:
ret half 0xH4FC1
}
; CHECK-ILLEGAL: .[[LBL6:LCPI6_[0-9]]]:
; CHECK-ILLEGAL-NEXT: .hword 20417 // half 31.016
; CHECK-ILLEGAL-LABEL: Const6:
; CHECK-ILLEGAL: adrp x[[NUM:[0-9]+]], .[[LBL6]]
; CHECK-ILLEGAL-NEXT: ldr h0, [x[[NUM]], :lo12:.[[LBL6]]]
define half @Const7() {
entry:
ret half 0xH5000
}
; CHECK-ILLEGAL: .[[LBL7:LCPI7_[0-9]]]:
; CHECK-ILLEGAL-NEXT: .hword 20480 // half 32
; CHECK-ILLEGAL-LABEL: Const7:
; CHECK-ILLEGAL: adrp x[[NUM:[0-9]+]], .[[LBL7]]
; CHECK-ILLEGAL-NEXT: ldr h0, [x[[NUM]], :lo12:.[[LBL7]]]

File diff suppressed because it is too large Load Diff