Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -127,11 +127,58 @@ } }; +// This structure keeps tabs on which arch modifying directives +// have been used, and if the header is over, and the code has +// started (first call to emit a function label). +// We use this to warn on duplicated use of those directives, or +// when they're used inside functions, since they leak the attribute +// to the rest of the file (not always intentional). +class ArchDirectiveMap { + SMLoc Arch; + SMLoc ArchExt; + SMLoc CPU; + SMLoc FPU; + bool Started = false; + MCAsmParser &Parser; + + void check(SMLoc &Prev, SMLoc &Loc, Twine &Name) { + if (Prev.isValid()) { + Parser.Warning(Loc, Name + " used more than once"); + Parser.Warning(Prev, Name + " previously defined here"); + } + Prev = Loc; + if (Started) + Parser.Warning(Loc, Name + " used outside header"); + } +public: + ArchDirectiveMap(MCAsmParser &Parser) : Parser(Parser) {} + void checkArch(SMLoc &Loc) { + Twine Name(".arch"); + check(Arch, Loc, Name); + } + void checkArchExt(SMLoc &Loc) { + Twine Name(".arch_extension"); + check(ArchExt, Loc, Name); + } + void checkCPU(SMLoc &Loc) { + Twine Name(".cpu"); + check(CPU, Loc, Name); + } + void checkFPU(SMLoc &Loc) { + Twine Name(".fpu"); + check(FPU, Loc, Name); + } + void start() { + Started = true; + } +}; + class ARMAsmParser : public MCTargetAsmParser { MCSubtargetInfo &STI; const MCInstrInfo &MII; const MCRegisterInfo *MRI; UnwindContext UC; + ArchDirectiveMap ADM; ARMTargetStreamer &getTargetStreamer() { assert(getParser().getStreamer().getTargetStreamer() && @@ -349,7 +396,7 @@ ARMAsmParser(MCSubtargetInfo &STI, MCAsmParser &Parser, const MCInstrInfo &MII, const MCTargetOptions &Options) - : STI(STI), MII(MII), UC(Parser) { + : STI(STI), MII(MII), UC(Parser), ADM(Parser) { MCAsmParserExtension::Initialize(Parser); // Cache the MCRegisterInfo. @@ -8933,6 +8980,7 @@ getParser().getStreamer().EmitThumbFunc(Symbol); NextSymbolIsThumb = false; } + ADM.start(); } /// parseDirectiveThumbFunc @@ -9094,6 +9142,8 @@ /// parseDirectiveArch /// ::= .arch token bool ARMAsmParser::parseDirectiveArch(SMLoc L) { + ADM.checkArch(L); + StringRef Arch = getParser().parseStringToEndOfStatement().trim(); unsigned ID = ARMTargetParser::parseArch(Arch); @@ -9222,6 +9272,8 @@ /// parseDirectiveCPU /// ::= .cpu str bool ARMAsmParser::parseDirectiveCPU(SMLoc L) { + ADM.checkCPU(L); + StringRef CPU = getParser().parseStringToEndOfStatement().trim(); getTargetStreamer().emitTextAttribute(ARMBuildAttrs::CPU_name, CPU); @@ -9240,6 +9292,8 @@ /// parseDirectiveFPU /// ::= .fpu str bool ARMAsmParser::parseDirectiveFPU(SMLoc L) { + ADM.checkFPU(L); + SMLoc FPUNameLoc = getTok().getLoc(); StringRef FPU = getParser().parseStringToEndOfStatement().trim(); @@ -9997,6 +10051,8 @@ /// parseDirectiveArchExtension /// ::= .arch_extension [no]feature bool ARMAsmParser::parseDirectiveArchExtension(SMLoc L) { + ADM.checkArchExt(L); + MCAsmParser &Parser = getParser(); if (getLexer().isNot(AsmToken::Identifier)) { Index: test/MC/ARM/directive-warning.s =================================================================== --- /dev/null +++ test/MC/ARM/directive-warning.s @@ -0,0 +1,58 @@ +@ RUN: llvm-mc -triple armv7-eabi %s 2>&1 | FileCheck %s + + + .text + @ Ok, in header + .cpu cortex-a8 + .fpu vfpv3 + .globl main + .align 2 + .type main,%function +main: + @ VFP3, ok + VMOV.F64 d0, d1 + bl lr +.Lfunc_end0: + .size main, .Lfunc_end0-main + + .globl neon + .align 2 + .type neon,%function +neon: + .fpu neon +@ CHECK: directive-warning.s:{{.*}} warning: .fpu used more than once +@ CHECK-NEXT: .fpu neon +@ CHECK: directive-warning.s:{{.*}} warning: .fpu previously defined here +@ CHECK-NEXT: .fpu vfpv3 +@ CHECK: directive-warning.s:{{.*}} warning: .fpu used outside header +@ CHECK-NEXT: .fpu neon + @ NEON, ok, but warn + VMLA.U32 d1, d2, d3 + bl lr +.Lfunc_end1: + .size neon, .Lfunc_end1-neon + + .globl vfp3 + .align 2 + .type vfp3,%function +vfp3: + @ NEON, not ok, but can't warn + VMOV d0, d1 + bl lr +.Lfunc_end2: + .size vfp3, .Lfunc_end2-vfp3 + + @ Post-header declaration, not ok, warn + .arch_extension idiv + .cpu cortex-a15 + .arch armv4 +@ CHECK: directive-warning.s:{{.*}} warning: .arch_extension used outside header +@ CHECK: .arch_extension idiv +@ CHECK: directive-warning.s:{{.*}} warning: .cpu used more than once +@ CHECK: .cpu cortex-a15 +@ CHECK: directive-warning.s:{{.*}} warning: .cpu previously defined here +@ CHECK: .cpu cortex-a8 +@ CHECK: directive-warning.s:{{.*}} warning: .cpu used outside header +@ CHECK: .cpu cortex-a15 +@ CHECK: directive-warning.s:{{.*}} warning: .arch used outside header +@ CHECK: .arch armv4