diff --git a/llvm/lib/Target/ARM/ARMInstrVFP.td b/llvm/lib/Target/ARM/ARMInstrVFP.td index 0912b473cbb5..a5494819d166 100644 --- a/llvm/lib/Target/ARM/ARMInstrVFP.td +++ b/llvm/lib/Target/ARM/ARMInstrVFP.td @@ -207,6 +207,27 @@ defm VSTM : vfp_ldst_mult<"vstm", 0, IIC_fpStore_m, IIC_fpStore_mu>; def : MnemonicAlias<"vldm", "vldmia">; def : MnemonicAlias<"vstm", "vstmia">; +// FLDM/FSTM - Load / Store multiple single / double precision registers for +// pre-ARMv6 cores. +// These instructions are deprecated! +def : VFP2MnemonicAlias<"fldmias", "vldmia">; +def : VFP2MnemonicAlias<"fldmdbs", "vldmdb">; +def : VFP2MnemonicAlias<"fldmeas", "vldmdb">; +def : VFP2MnemonicAlias<"fldmfds", "vldmia">; +def : VFP2MnemonicAlias<"fldmiad", "vldmia">; +def : VFP2MnemonicAlias<"fldmdbd", "vldmdb">; +def : VFP2MnemonicAlias<"fldmead", "vldmdb">; +def : VFP2MnemonicAlias<"fldmfdd", "vldmia">; + +def : VFP2MnemonicAlias<"fstmias", "vstmia">; +def : VFP2MnemonicAlias<"fstmdbs", "vstmdb">; +def : VFP2MnemonicAlias<"fstmeas", "vstmia">; +def : VFP2MnemonicAlias<"fstmfds", "vstmdb">; +def : VFP2MnemonicAlias<"fstmiad", "vstmia">; +def : VFP2MnemonicAlias<"fstmdbd", "vstmdb">; +def : VFP2MnemonicAlias<"fstmead", "vstmia">; +def : VFP2MnemonicAlias<"fstmfdd", "vstmdb">; + def : InstAlias<"vpush${p} $r", (VSTMDDB_UPD SP, pred:$p, dpr_reglist:$r)>, Requires<[HasVFP2]>; def : InstAlias<"vpush${p} $r", (VSTMSDB_UPD SP, pred:$p, spr_reglist:$r)>, @@ -247,7 +268,7 @@ multiclass vfp_ldstx_mult { AXXI4<(outs GPR:$wb), (ins GPR:$Rn, pred:$p, dpr_reglist:$regs, variable_ops), IndexModeUpd, !strconcat(asm, "dbx${p}\t$Rn!, $regs"), "$Rn = $wb", []> { let Inst{24-23} = 0b10; // Decrement Before - let Inst{21} = 1; + let Inst{21} = 1; // Writeback let Inst{20} = L_bit; } } @@ -255,6 +276,12 @@ multiclass vfp_ldstx_mult { defm FLDM : vfp_ldstx_mult<"fldm", 1>; defm FSTM : vfp_ldstx_mult<"fstm", 0>; +def : VFP2MnemonicAlias<"fldmeax", "fldmdbx">; +def : VFP2MnemonicAlias<"fldmfdx", "fldmiax">; + +def : VFP2MnemonicAlias<"fstmeax", "fstmiax">; +def : VFP2MnemonicAlias<"fstmfdx", "fstmdbx">; + //===----------------------------------------------------------------------===// // FP Binary Operations. // diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index d4122bcb4af2..c0e547234695 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -5111,6 +5111,15 @@ static void applyMnemonicAliases(StringRef &Mnemonic, unsigned Features, bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, SmallVectorImpl &Operands) { + // FIXME: Can this be done via tablegen in some fashion? + bool HasPrecisionRestrictions; + bool AcceptDoublePrecisionOnly; + bool AcceptSinglePrecisionOnly; + HasPrecisionRestrictions = Name.startswith("fldm") || Name.startswith("fstm"); + AcceptDoublePrecisionOnly = + HasPrecisionRestrictions && (Name.back() == 'd' || Name.back() == 'x'); + AcceptSinglePrecisionOnly = HasPrecisionRestrictions && Name.back() == 's'; + // Apply mnemonic aliases before doing anything else, as the destination // mnemonic may include suffices and we want to handle them normally. // The generic tblgen'erated code does this later, at the start of @@ -5279,6 +5288,26 @@ bool ARMAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, Parser.Lex(); // Consume the EndOfStatement + if (HasPrecisionRestrictions) { + ARMOperand *Op = static_cast(Operands.back()); + assert(Op->isRegList()); + const SmallVectorImpl &RegList = Op->getRegList(); + for (SmallVectorImpl::const_iterator RLI = RegList.begin(), + RLE = RegList.end(); + RLI != RLE; ++RLI) { + if (AcceptSinglePrecisionOnly && + !ARMMCRegisterClasses[ARM::SPRRegClassID].contains(*RLI)) + return Error(Op->getStartLoc(), + "VFP/Neon single precision register expected"); + else if (AcceptDoublePrecisionOnly && + !ARMMCRegisterClasses[ARM::DPRRegClassID].contains(*RLI)) + return Error(Op->getStartLoc(), + "VFP/Neon double precision register expected"); + else + llvm_unreachable("must have single or double precision restrictions"); + } + } + // Some instructions, mostly Thumb, have forms for the same mnemonic that // do and don't have a cc_out optional-def operand. With some spot-checks // of the operand list, we can figure out which variant we're trying to diff --git a/llvm/test/MC/ARM/vfp-aliases-diagnostics.s b/llvm/test/MC/ARM/vfp-aliases-diagnostics.s new file mode 100644 index 000000000000..911c23b23583 --- /dev/null +++ b/llvm/test/MC/ARM/vfp-aliases-diagnostics.s @@ -0,0 +1,97 @@ +@ RUN: not llvm-mc -triple armv7-eabi -filetype asm -o /dev/null %s 2>&1 \ +@ RUN: | FileCheck %s + + .syntax unified + .fpu vfp + + .type aliases,%function +aliases: + fstmfdd sp!, {s0} + fstmead sp!, {s0} + fstmdbd sp!, {s0} + fstmiad sp!, {s0} + fstmfds sp!, {d0} + fstmeas sp!, {d0} + fstmdbs sp!, {d0} + fstmias sp!, {d0} + + fldmias sp!, {d0} + fldmdbs sp!, {d0} + fldmeas sp!, {d0} + fldmfds sp!, {d0} + fldmiad sp!, {s0} + fldmdbd sp!, {s0} + fldmead sp!, {s0} + fldmfdd sp!, {s0} + + fstmeax sp!, {s0} + fldmfdx sp!, {s0} + + fstmfdx sp!, {s0} + fldmeax sp!, {s0} + +@ CHECK-LABEL: aliases +@ CHECK: error: VFP/Neon double precision register expected +@ CHECK: fstmfdd sp!, {s0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon double precision register expected +@ CHECK: fstmead sp!, {s0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon double precision register expected +@ CHECK: fstmdbd sp!, {s0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon double precision register expected +@ CHECK: fstmiad sp!, {s0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon single precision register expected +@ CHECK: fstmfds sp!, {d0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon single precision register expected +@ CHECK: fstmeas sp!, {d0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon single precision register expected +@ CHECK: fstmdbs sp!, {d0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon single precision register expected +@ CHECK: fstmias sp!, {d0} +@ CHECK: ^ + +@ CHECK: error: VFP/Neon single precision register expected +@ CHECK: fldmias sp!, {d0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon single precision register expected +@ CHECK: fldmdbs sp!, {d0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon single precision register expected +@ CHECK: fldmeas sp!, {d0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon single precision register expected +@ CHECK: fldmfds sp!, {d0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon double precision register expected +@ CHECK: fldmiad sp!, {s0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon double precision register expected +@ CHECK: fldmdbd sp!, {s0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon double precision register expected +@ CHECK: fldmead sp!, {s0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon double precision register expected +@ CHECK: fldmfdd sp!, {s0} +@ CHECK: ^ + +@ CHECK: error: VFP/Neon double precision register expected +@ CHECK: fstmeax sp!, {s0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon double precision register expected +@ CHECK: fldmfdx sp!, {s0} +@ CHECK: ^ + +@ CHECK: error: VFP/Neon double precision register expected +@ CHECK: fstmfdx sp!, {s0} +@ CHECK: ^ +@ CHECK: error: VFP/Neon double precision register expected +@ CHECK: fldmeax sp!, {s0} +@ CHECK: ^ + diff --git a/llvm/test/MC/ARM/vfp-aliases.s b/llvm/test/MC/ARM/vfp-aliases.s new file mode 100644 index 000000000000..1ed6e53b80e9 --- /dev/null +++ b/llvm/test/MC/ARM/vfp-aliases.s @@ -0,0 +1,53 @@ +@ RUN: llvm-mc -triple armv7-eabi -filetype asm -o - %s | FileCheck %s + + .syntax unified + .fpu vfp + + .type aliases,%function +aliases: + fstmfdd sp!, {d0} + fstmead sp!, {d0} + fstmdbd sp!, {d0} + fstmiad sp!, {d0} + fstmfds sp!, {s0} + fstmeas sp!, {s0} + fstmdbs sp!, {s0} + fstmias sp!, {s0} + + fldmias sp!, {s0} + fldmdbs sp!, {s0} + fldmeas sp!, {s0} + fldmfds sp!, {s0} + fldmiad sp!, {d0} + fldmdbd sp!, {d0} + fldmead sp!, {d0} + fldmfdd sp!, {d0} + + fstmeax sp!, {d0} + fldmfdx sp!, {d0} + + fstmfdx sp!, {d0} + fldmeax sp!, {d0} + +@ CHECK-LABEL: aliases +@ CHECK: vpush {d0} +@ CHECK: vstmia sp!, {d0} +@ CHECK: vpush {d0} +@ CHECK: vstmia sp!, {d0} +@ CHECK: vpush {s0} +@ CHECK: vstmia sp!, {s0} +@ CHECK: vpush {s0} +@ CHECK: vstmia sp!, {s0} +@ CHECK: vpop {s0} +@ CHECK: vldmdb sp!, {s0} +@ CHECK: vldmdb sp!, {s0} +@ CHECK: vpop {s0} +@ CHECK: vpop {d0} +@ CHECK: vldmdb sp!, {d0} +@ CHECK: vldmdb sp!, {d0} +@ CHECK: vpop {d0} +@ CHECK: fstmiax sp!, {d0} +@ CHECK: fldmiax sp!, {d0} +@ CHECK: fstmdbx sp!, {d0} +@ CHECK: fldmdbx sp!, {d0} +