Add support for ARM / Thumb mode switching with .code 16 and .code 32.
authorEvan Cheng <evan.cheng@apple.com>
Fri, 8 Jul 2011 22:36:29 +0000 (22:36 +0000)
committerEvan Cheng <evan.cheng@apple.com>
Fri, 8 Jul 2011 22:36:29 +0000 (22:36 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@134760 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/AsmParser/ARMAsmParser.cpp
test/MC/ARM/mode-switch.s [new file with mode: 0644]

index 9438ee177576e0b60478d222dc97088951988578..58ffe32333e75e49e9b1b7badb1abdd512b23a45 100644 (file)
@@ -42,7 +42,11 @@ class ARMOperand;
 
 class ARMAsmParser : public TargetAsmParser {
   MCAsmParser &Parser;
-  OwningPtr<const MCSubtargetInfo> STI;
+  /// STI, ARM_STI, Thumb_STI - Subtarget info for ARM and Thumb modes. STI
+  /// points to either ARM_STI or Thumb_STI depending on the mode.
+  const MCSubtargetInfo *STI;
+  OwningPtr<const MCSubtargetInfo> ARM_STI;
+  OwningPtr<const MCSubtargetInfo> Thumb_STI;
 
   MCAsmParser &getParser() const { return Parser; }
   MCAsmLexer &getLexer() const { return Parser.getLexer(); }
@@ -89,10 +93,13 @@ class ARMAsmParser : public TargetAsmParser {
     // FIXME: Can tablegen auto-generate this?
     return (STI->getFeatureBits() & ARM::ModeThumb) != 0;
   }
-
   bool isThumbOne() const {
     return isThumb() && (STI->getFeatureBits() & ARM::FeatureThumb2) == 0;
   }
+  void SwitchMode() {
+    STI = isThumb() ? ARM_STI.get() : Thumb_STI.get();
+    setAvailableFeatures(ComputeAvailableFeatures(STI->getFeatureBits()));
+  }
 
   /// @name Auto-generated Match Functions
   /// {
@@ -129,10 +136,24 @@ class ARMAsmParser : public TargetAsmParser {
 
 public:
   ARMAsmParser(StringRef TT, StringRef CPU, StringRef FS, MCAsmParser &_Parser)
-    : TargetAsmParser(), Parser(_Parser),
-      STI(ARM_MC::createARMMCSubtargetInfo(TT, CPU, FS)) {
-
+    : TargetAsmParser(), Parser(_Parser) {
     MCAsmParserExtension::Initialize(_Parser);
+
+    STI = ARM_MC::createARMMCSubtargetInfo(TT, CPU, FS);
+    // FIXME: Design a better way to create two subtargets with only difference
+    // being a feature change.
+    if (isThumb()) {
+      Thumb_STI.reset(STI);
+      assert(TT.startswith("thumb") && "Unexpected Triple string for Thumb!");
+      Twine ARM_TT = "arm" + TT.substr(5);
+      ARM_STI.reset(ARM_MC::createARMMCSubtargetInfo(ARM_TT.str(), CPU, FS));
+    } else {
+      ARM_STI.reset(STI);
+      assert(TT.startswith("arm") && "Unexpected Triple string for ARM!");
+      Twine Thumb_TT = "thumb" + TT.substr(3);
+      Thumb_STI.reset(ARM_MC::createARMMCSubtargetInfo(Thumb_TT.str(),CPU, FS));
+    }
+
     // Initialize the set of available features.
     setAvailableFeatures(ComputeAvailableFeatures(STI->getFeatureBits()));
   }
@@ -2215,18 +2236,11 @@ bool ARMAsmParser::ParseDirectiveCode(SMLoc L) {
     return Error(Parser.getTok().getLoc(), "unexpected token in directive");
   Parser.Lex();
 
-  // FIXME: We need to be able switch subtargets at this point so that
-  // MatchInstructionImpl() will work when it gets the AvailableFeatures which
-  // includes Feature_IsThumb or not to match the right instructions.  This is
-  // blocked on the FIXME in llvm-mc.cpp when creating the TargetMachine.
-  if (Val == 16){
-    assert(isThumb() &&
-          "switching between arm/thumb not yet suppported via .code 16)");
+  if (Val == 16) {
+    if (!isThumb()) SwitchMode();
     getParser().getStreamer().EmitAssemblerFlag(MCAF_Code16);
-  }
-  else{
-    assert(!isThumb() &&
-           "switching between thumb/arm not yet suppported via .code 32)");
+  } else {
+    if (isThumb()) SwitchMode();
     getParser().getStreamer().EmitAssemblerFlag(MCAF_Code32);
    }
 
diff --git a/test/MC/ARM/mode-switch.s b/test/MC/ARM/mode-switch.s
new file mode 100644 (file)
index 0000000..1fad8f1
--- /dev/null
@@ -0,0 +1,16 @@
+@ Test ARM / Thumb mode switching with .code
+@ RUN: llvm-mc -mcpu=cortex-a8 -triple arm-unknown-unknown -show-encoding < %s | FileCheck %s
+
+.code 16
+
+@ CHECK:       add.w   r0, r0, r1              @ encoding: [0x01,0x00,0x00,0xeb]
+       add.w   r0, r0, r1
+
+.code 32
+@ CHECK:       add     r0, r0, r1              @ encoding: [0x01,0x00,0x80,0xe0]
+       add     r0, r0, r1
+
+.code 16
+@ CHECK:       add     r0, r0, r1              @ encoding: [0x40,0x18]
+        
+        add     r0, r0, r1