Index: cfe/trunk/lib/Driver/ToolChains/Arch/ARM.cpp =================================================================== --- cfe/trunk/lib/Driver/ToolChains/Arch/ARM.cpp +++ cfe/trunk/lib/Driver/ToolChains/Arch/ARM.cpp @@ -376,7 +376,11 @@ Features.push_back( Args.MakeArgString((F.second ? "+" : "-") + F.first())); } else if (!CPUName.empty()) { - DecodeARMFeaturesFromCPU(D, CPUName, ExtensionFeatures); + // This sets the default features for the specified CPU. We certainly don't + // want to override the features that have been explicitly specified on the + // command line. Therefore, process them directly instead of appending them + // at the end later. + DecodeARMFeaturesFromCPU(D, CPUName, Features); } if (CPUArg) Index: cfe/trunk/test/CodeGen/arm-target-features.c =================================================================== --- cfe/trunk/test/CodeGen/arm-target-features.c +++ cfe/trunk/test/CodeGen/arm-target-features.c @@ -32,7 +32,7 @@ // RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu exynos-m4 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V82 // RUN: %clang_cc1 -triple thumbv8-linux-gnueabihf -target-cpu exynos-m5 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V82 -// CHECK-BASIC-V82: "target-features"="+armv8.2-a,+crc,+crypto,+d32,+dotprod,+dsp,+fp-armv8,+fp-armv8d16,+fp-armv8d16sp,+fp-armv8sp,+fp16,+fp64,+fpregs,+hwdiv,+hwdiv-arm,+neon,+ras,+thumb-mode,+vfp2,+vfp2d16,+vfp2d16sp,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,+vfp4,+vfp4d16,+vfp4d16sp,+vfp4sp" +// CHECK-BASIC-V82: "target-features"="+armv8.2-a,+crc,+crypto,+d32,+dotprod,+dsp,+fp-armv8,+fp-armv8d16,+fp-armv8d16sp,+fp-armv8sp,+fp16,+fp64,+fpregs,+fullfp16,+hwdiv,+hwdiv-arm,+neon,+ras,+thumb-mode,+vfp2,+vfp2d16,+vfp2d16sp,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,+vfp4,+vfp4d16,+vfp4d16sp,+vfp4sp" // RUN: %clang_cc1 -triple armv8-linux-gnueabi -target-cpu cortex-a53 -emit-llvm -o - %s | FileCheck %s --check-prefix=CHECK-BASIC-V8-ARM // CHECK-BASIC-V8-ARM: "target-features"="+armv8-a,+crc,+crypto,+d32,+dsp,+fp-armv8,+fp-armv8d16,+fp-armv8d16sp,+fp-armv8sp,+fp16,+fp64,+fpregs,+hwdiv,+hwdiv-arm,+neon,+vfp2,+vfp2d16,+vfp2d16sp,+vfp2sp,+vfp3,+vfp3d16,+vfp3d16sp,+vfp3sp,+vfp4,+vfp4d16,+vfp4d16sp,+vfp4sp,-thumb-mode" Index: llvm/trunk/include/llvm/Support/ARMTargetParser.def =================================================================== --- llvm/trunk/include/llvm/Support/ARMTargetParser.def +++ llvm/trunk/include/llvm/Support/ARMTargetParser.def @@ -148,6 +148,7 @@ ARM_ARCH_EXT_NAME("dotprod", ARM::AEK_DOTPROD, "+dotprod","-dotprod") ARM_ARCH_EXT_NAME("dsp", ARM::AEK_DSP, "+dsp", "-dsp") ARM_ARCH_EXT_NAME("fp", ARM::AEK_FP, nullptr, nullptr) +ARM_ARCH_EXT_NAME("fp.dp", ARM::AEK_FP_DP, nullptr, nullptr) ARM_ARCH_EXT_NAME("mve", ARM::AEK_SIMD, "+mve", "-mve") ARM_ARCH_EXT_NAME("mve.fp", (ARM::AEK_SIMD | ARM::AEK_FP), "+mve.fp", "-mve.fp") ARM_ARCH_EXT_NAME("idiv", (ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB), nullptr, nullptr) Index: llvm/trunk/lib/Support/ARMTargetParser.cpp =================================================================== --- llvm/trunk/lib/Support/ARMTargetParser.cpp +++ llvm/trunk/lib/Support/ARMTargetParser.cpp @@ -409,30 +409,12 @@ if (Extensions == AEK_INVALID) return false; - if (Extensions & AEK_CRC) - Features.push_back("+crc"); - else - Features.push_back("-crc"); - - if (Extensions & AEK_DSP) - Features.push_back("+dsp"); - else - Features.push_back("-dsp"); - - if (Extensions & AEK_FP16FML) - Features.push_back("+fp16fml"); - else - Features.push_back("-fp16fml"); - - if (Extensions & AEK_RAS) - Features.push_back("+ras"); - else - Features.push_back("-ras"); - - if (Extensions & AEK_DOTPROD) - Features.push_back("+dotprod"); - else - Features.push_back("-dotprod"); + for (const auto AE : ARCHExtNames) { + if ((Extensions & AE.ID) == AE.ID && AE.Feature) + Features.push_back(AE.Feature); + else if (AE.NegFeature) + Features.push_back(AE.NegFeature); + } return getHWDivFeatures(Extensions, Features); } Index: llvm/trunk/unittests/Support/TargetParserTest.cpp =================================================================== --- llvm/trunk/unittests/Support/TargetParserTest.cpp +++ llvm/trunk/unittests/Support/TargetParserTest.cpp @@ -571,17 +571,18 @@ TEST(TargetParserTest, ARMExtensionFeatures) { std::map> Extensions; - Extensions[ARM::AEK_CRC] = { "+crc", "-crc" }; - Extensions[ARM::AEK_DSP] = { "+dsp", "-dsp" }; + for (auto &Ext : ARM::ARCHExtNames) { + if (Ext.Feature && Ext.NegFeature) + Extensions[Ext.ID] = { StringRef(Ext.Feature), + StringRef(Ext.NegFeature) }; + } + Extensions[ARM::AEK_HWDIVARM] = { "+hwdiv-arm", "-hwdiv-arm" }; Extensions[ARM::AEK_HWDIVTHUMB] = { "+hwdiv", "-hwdiv" }; - Extensions[ARM::AEK_RAS] = { "+ras", "-ras" }; - Extensions[ARM::AEK_FP16FML] = { "+fp16fml", "-fp16fml" }; - Extensions[ARM::AEK_DOTPROD] = { "+dotprod", "-dotprod" }; std::vector Features; - EXPECT_FALSE(AArch64::getExtensionFeatures(ARM::AEK_INVALID, Features)); + EXPECT_FALSE(ARM::getExtensionFeatures(ARM::AEK_INVALID, Features)); for (auto &E : Extensions) { // test +extension @@ -598,7 +599,7 @@ Found = std::find(std::begin(Features), std::end(Features), E.second.at(1)); EXPECT_TRUE(Found != std::end(Features)); EXPECT_TRUE(Extensions.size() == Features.size()); - } + } } TEST(TargetParserTest, ARMFPUFeatures) {