Index: include/llvm/Support/TargetParser.h =================================================================== --- include/llvm/Support/TargetParser.h +++ include/llvm/Support/TargetParser.h @@ -30,13 +30,16 @@ // FPU names. enum FPUKind { FK_INVALID = 0, + FK_NONE, FK_VFP, FK_VFPV2, FK_VFPV3, FK_VFPV3_D16, FK_VFPV4, FK_VFPV4_D16, + FK_FPV4_SP_D16, FK_FPV5_D16, + FK_FPV5_SP_D16, FK_FP_ARMV8, FK_NEON, FK_NEON_VFPV4, Index: lib/Support/TargetParser.cpp =================================================================== --- lib/Support/TargetParser.cpp +++ lib/Support/TargetParser.cpp @@ -51,13 +51,16 @@ FPURestriction Restriction; } FPUNames[] = { { "invalid", ARM::FK_INVALID, 0, NS_None, FR_None}, + { "none", ARM::FK_NONE, 0, NS_None, FR_None}, { "vfp", ARM::FK_VFP, 2, NS_None, FR_None}, { "vfpv2", ARM::FK_VFPV2, 2, NS_None, FR_None}, { "vfpv3", ARM::FK_VFPV3, 3, NS_None, FR_None}, { "vfpv3-d16", ARM::FK_VFPV3_D16, 3, NS_None, FR_D16}, { "vfpv4", ARM::FK_VFPV4, 4, NS_None, FR_None}, { "vfpv4-d16", ARM::FK_VFPV4_D16, 4, NS_None, FR_D16}, + { "fpv4-sp-d16", ARM::FK_FPV4_SP_D16, 4, NS_None, FR_SP_D16}, { "fpv5-d16", ARM::FK_FPV5_D16, 5, NS_None, FR_D16}, + { "fpv5-sp-d16", ARM::FK_FPV5_SP_D16, 5, NS_None, FR_SP_D16}, { "fp-armv8", ARM::FK_FP_ARMV8, 5, NS_None, FR_None}, { "neon", ARM::FK_NEON, 3, NS_Neon, FR_None}, { "neon-vfpv4", ARM::FK_NEON_VFPV4, 4, NS_Neon, FR_None}, @@ -376,10 +379,9 @@ .Case("vfp4", "vfpv4") .Case("vfp3-d16", "vfpv3-d16") .Case("vfp4-d16", "vfpv4-d16") - // FIXME: sp-16 is NOT the same as d16 - .Cases("fp4-sp-d16", "fpv4-sp-d16", "vfpv4-d16") + .Cases("fp4-sp-d16", "vfpv4-sp-d16", "fpv4-sp-d16") .Cases("fp4-dp-d16", "fpv4-dp-d16", "vfpv4-d16") - .Cases("fp5-sp-d16", "fpv5-sp-d16", "fpv5-d16") + .Case("fp5-sp-d16", "fpv5-sp-d16") .Cases("fp5-dp-d16", "fpv5-dp-d16", "fpv5-d16") // FIXME: Clang uses it, but it's bogus, since neon defaults to vfpv3. .Case("neon-vfpv3", "neon") Index: lib/Target/ARM/ARMAsmPrinter.cpp =================================================================== --- lib/Target/ARM/ARMAsmPrinter.cpp +++ lib/Target/ARM/ARMAsmPrinter.cpp @@ -640,9 +640,13 @@ if (STI.hasFPARMv8()) // FPv5 and FP-ARMv8 have the same instructions, so are modeled as one // FPU, but there are two different names for it depending on the CPU. - ATS.emitFPU(STI.hasD16() ? ARM::FK_FPV5_D16 : ARM::FK_FP_ARMV8); + ATS.emitFPU(STI.hasD16() + ? (STI.isFPOnlySP() ? ARM::FK_FPV5_SP_D16 : ARM::FK_FPV5_D16) + : ARM::FK_FP_ARMV8); else if (STI.hasVFP4()) - ATS.emitFPU(STI.hasD16() ? ARM::FK_VFPV4_D16 : ARM::FK_VFPV4); + ATS.emitFPU(STI.hasD16() + ? (STI.isFPOnlySP() ? ARM::FK_FPV4_SP_D16 : ARM::FK_VFPV4_D16) + : ARM::FK_VFPV4); else if (STI.hasVFP3()) ATS.emitFPU(STI.hasD16() ? ARM::FK_VFPV3_D16 : ARM::FK_VFPV3); else if (STI.hasVFP2()) Index: lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -810,6 +810,9 @@ /* OverwriteExisting= */ false); break; + // ABI_HardFP_use is handled in ARMAsmPrinter, so _SP_D16 is treated the same + // as _D16 here. + case ARM::FK_FPV4_SP_D16: case ARM::FK_VFPV4_D16: setAttributeItem(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPv4B, @@ -824,6 +827,7 @@ // FPV5_D16 is identical to FP_ARMV8 except for the number of D registers, so // uses the FP_ARMV8_D16 build attribute. + case ARM::FK_FPV5_SP_D16: case ARM::FK_FPV5_D16: setAttributeItem(ARMBuildAttrs::FP_arch, ARMBuildAttrs::AllowFPARMv8B, @@ -858,6 +862,7 @@ break; case ARM::FK_SOFTVFP: + case ARM::FK_NONE: break; default: Index: test/CodeGen/ARM/build-attributes.ll =================================================================== --- test/CodeGen/ARM/build-attributes.ll +++ test/CodeGen/ARM/build-attributes.ll @@ -923,7 +923,7 @@ ; CORTEX-M4-SOFT: .eabi_attribute 7, 77 ; CORTEX-M4-SOFT: .eabi_attribute 8, 0 ; CORTEX-M4-SOFT: .eabi_attribute 9, 2 -; CORTEX-M4-SOFT: .fpu vfpv4-d16 +; CORTEX-M4-SOFT: .fpu fpv4-sp-d16 ; CORTEX-M4-SOFT-NOT: .eabi_attribute 19 ;; We default to IEEE 754 compliance ; CORTEX-M4-SOFT: .eabi_attribute 20, 1 @@ -953,7 +953,7 @@ ; CORTEX-M4-HARD: .eabi_attribute 7, 77 ; CORTEX-M4-HARD: .eabi_attribute 8, 0 ; CORTEX-M4-HARD: .eabi_attribute 9, 2 -; CORTEX-M4-HARD: .fpu vfpv4-d16 +; CORTEX-M4-HARD: .fpu fpv4-sp-d16 ; CORTEX-M4-HARD-NOT: .eabi_attribute 19 ;; We default to IEEE 754 compliance ; CORTEX-M4-HARD: .eabi_attribute 20, 1 @@ -984,7 +984,7 @@ ; CORTEX-M7: .eabi_attribute 8, 0 ; CORTEX-M7: .eabi_attribute 9, 2 ; CORTEX-M7-SOFT-NOT: .fpu -; CORTEX-M7-SINGLE: .fpu fpv5-d16 +; CORTEX-M7-SINGLE: .fpu fpv5-sp-d16 ; CORTEX-M7-DOUBLE: .fpu fpv5-d16 ; CORTEX-M7: .eabi_attribute 17, 1 ; CORTEX-M7-NOT: .eabi_attribute 19 Index: test/MC/ARM/directive-fpu-multiple.s =================================================================== --- test/MC/ARM/directive-fpu-multiple.s +++ test/MC/ARM/directive-fpu-multiple.s @@ -1,12 +1,28 @@ @ Check multiple .fpu directives. @ The later .fpu directive should overwrite the earlier one. -@ See also: directive-fpu-multiple2.s. +@ We also check here that all the .fpu directives that we expect to work do work @ RUN: llvm-mc -triple arm-eabi -filetype obj %s | llvm-readobj -arm-attributes \ @ RUN: | FileCheck %s -check-prefix CHECK-ATTR + .fpu none + .fpu vfp + .fpu vfpv2 + .fpu vfpv3 + .fpu vfpv3-d16 + .fpu vfpv4 + .fpu vfpv4-d16 + .fpu fpv4-sp-d16 + .fpu fpv5-d16 + .fpu fpv5-sp-d16 + .fpu fp-armv8 .fpu neon + .fpu neon-vfpv4 + .fpu neon-fp-armv8 + .fpu crypto-neon-fp-armv8 + .fpu softvfp + .fpu vfpv4 @ CHECK-ATTR: FileAttributes { Index: test/MC/ARM/directive-fpu-none.s =================================================================== --- /dev/null +++ test/MC/ARM/directive-fpu-none.s @@ -0,0 +1,37 @@ +@ RUN: not llvm-mc -triple armv8 -mattr=+neon,+crypto -o /dev/null %s 2>&1 \ +@ RUN: | FileCheck %s + + .text + +@ .fpu none should be accepted and disable all floating-point and neon +@ instructions. + + .fpu none +@ CHECK-NOT: error: Unknown FPU name + + vmov.f32 s0, s1 +@ CHECK: error: instruction requires: VFP2 +@ CHECK: vmov.f32 s0, s1 + + vmov.f32 s0, #1.0 +@ We don't get a 'requires VFP3' error message because the VFP2 vmov instruction +@ is matched instead (despite also not being enabled) and #1.0 is invalid for +@ that instruction. +@ CHECK: error: invalid operand for instruction +@ CHECK: vmov.f32 s0, #1.0 + + vfma.f32 s0, s1, s2 +@ CHECK: error: instruction requires: VFP4 +@ CHECK: vfma.f32 s0, s1, s2 + + vmaxnm.f32 s0, s1, s2 +@ CHECK: error: instruction requires: FPARMv8 +@ CHECK: vmaxnm.f32 s0, s1, s2 + + vmull.p8 q0, d2, d4 +@ CHECK: error: instruction requires: NEON +@ CHECK: vmull.p8 q0, d2, d4 + + vmull.p64 q0, d2, d4 +@ CHECK: error: instruction requires: crypto +@ CHECK: vmull.p64 q0, d2, d4