Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -296,6 +296,7 @@ uint64_t FB = ComputeAvailableFeatures(STI.ToggleFeature(ARM::ModeThumb)); setAvailableFeatures(FB); } + void FixModeAfterArchChange(bool WasThumb, SMLoc Loc); bool isMClass() const { return getSTI().getFeatureBits()[ARM::FeatureMClass]; } @@ -9099,6 +9100,31 @@ return false; } +// After changing arch/CPU, try to put the ARM/Thumb mode back to what it was +// before, if supported by the new target, or emit mapping symbols for the mode +// switch. +void ARMAsmParser::FixModeAfterArchChange(bool WasThumb, SMLoc Loc) { + if (WasThumb != isThumb()) { + if (WasThumb && hasThumb()) { + // Stay in Thumb mode + SwitchMode(); + } else if (!WasThumb && hasARM()) { + // Stay in ARM mode + SwitchMode(); + } else { + // Mode switch forced, because the new arch doesn't support the old mode. + getParser().getStreamer().EmitAssemblerFlag(isThumb() ? MCAF_Code16 + : MCAF_Code32); + // Warn about the implcit mode switch. GAS does not switch modes here, + // but instead stays in the old mode, reporting an error on any following + // instructions as the mode does not exist on the target. + Warning(Loc, Twine("new target does not support ") + + (WasThumb ? "thumb" : "arm") + " mode, switching to " + + (!WasThumb ? "thumb" : "arm") + " mode"); + } + } +} + /// parseDirectiveArch /// ::= .arch token bool ARMAsmParser::parseDirectiveArch(SMLoc L) { @@ -9111,10 +9137,12 @@ return false; } + bool WasThumb = isThumb(); Triple T; MCSubtargetInfo &STI = copySTI(); STI.setDefaultFeatures("", ("+" + ARM::getArchName(ID)).str()); setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + FixModeAfterArchChange(WasThumb, L); getTargetStreamer().emitArch(ID); return false; @@ -9245,9 +9273,11 @@ return false; } + bool WasThumb = isThumb(); MCSubtargetInfo &STI = copySTI(); STI.setDefaultFeatures(CPU, ""); setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); + FixModeAfterArchChange(WasThumb, L); return false; } Index: test/MC/ARM/directive-arch-mode-switch.s =================================================================== --- /dev/null +++ test/MC/ARM/directive-arch-mode-switch.s @@ -0,0 +1,28 @@ +@ RUN: llvm-mc -triple arm-none-eabi -filetype asm %s 2>%t | FileCheck %s +@ RUN: FileCheck %s <%t --check-prefix=STDERR + +@ Start in arm mode + .arm +@ CHECK: .code 32 + +@ In ARM mode, switch to an arch which has ARM and Thumb, no warning or .code directive (stay in ARM mode) + .arch armv7-a +@ STDERR-NOT: [[@LINE-1]]:{{[0-9]+}}: warning: +@ CHECK-NOT: .code +@ CHECK: .arch armv7-a +@ CHECK-NOT: .code + +@ In ARM mode, switch to an arch which has Thumb only, expect warning and .code 16 directive + .arch armv6-m +@ STDERR: [[@LINE-1]]:{{[0-9]+}}: warning: new target does not support arm mode, switching to thumb mode +@ CHECK: .code 16 +@ CHECK: .arch armv6-m + +@ In Thumb mode, switch to an arch which has ARM and Thumb, no warning or .code directive (stay in Thumb mode) + .arch armv7-a +@ STDERR-NOT: [[@LINE-1]]:{{[0-9]+}}: warning: +@ CHECK-NOT: .code +@ CHECK: .arch armv7-a +@ CHECK-NOT: .code + +@ We don't have any ARM-only targets (i.e. v4), so we can't test the forced Thumb->ARM case