[llvm] 2273741 - [ARM] generate armv6m eXecute Only (XO) code

Ties Stuij via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 23 02:51:10 PDT 2023


Author: Ties Stuij
Date: 2023-06-23T10:50:47+01:00
New Revision: 2273741ea2547ecda28cb01d7679d0563b35ac16

URL: https://github.com/llvm/llvm-project/commit/2273741ea2547ecda28cb01d7679d0563b35ac16
DIFF: https://github.com/llvm/llvm-project/commit/2273741ea2547ecda28cb01d7679d0563b35ac16.diff

LOG: [ARM] generate armv6m eXecute Only (XO) code

[ARM] generate armv6m eXecute Only (XO) code for immediates, globals

Previously eXecute Only (XO) support was implemented for targets that support
MOVW/MOVT (~armv7+). See: https://reviews.llvm.org/D27449

XO prevents the compiler from generating data accesses to code sections. This
patch implements XO codegen for armv6-M, which does not support MOVW/MOVT, and
must resort to the following general pattern to avoid loads:

    movs    r3, :upper8_15:foo
    lsls    r3, #8
    adds    r3, :upper0_7:foo
    lsls    r3, #8
    adds    r3, :lower8_15:foo
    lsls    r3, #8
    adds    r3, :lower0_7:foo
    ldr     r3, [r3]

This is equivalent to the code pattern generated by GCC.

The above relocations are new to LLVM and have been implemented in a parent
patch: https://reviews.llvm.org/D149443.

This patch limits itself to implementing codegen for this pattern and enabling
XO for armv6-M in the backend.

Separate patches will follow for:
- switch tables
- replacing specific loads from constant islands which are spread out over the
  ARM backend codebase. Amongst others: FastISel, call lowering, stack frames.

Reviewed By: john.brawn

Differential Revision: https://reviews.llvm.org/D152795

Added: 
    

Modified: 
    llvm/lib/Target/ARM/ARMAsmPrinter.cpp
    llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
    llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
    llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
    llvm/lib/Target/ARM/ARMISelLowering.cpp
    llvm/lib/Target/ARM/ARMInstrThumb.td
    llvm/lib/Target/ARM/ARMMCInstLower.cpp
    llvm/lib/Target/ARM/ARMPredicates.td
    llvm/lib/Target/ARM/ARMSubtarget.cpp
    llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h
    llvm/test/CodeGen/ARM/execute-only-section.ll
    llvm/test/CodeGen/ARM/execute-only.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
index 6bc10429a4e0b..b1074d1265ff9 100644
--- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
+++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
@@ -199,6 +199,15 @@ void ARMAsmPrinter::PrintSymbolOperand(const MachineOperand &MO,
     O << ":lower16:";
   else if (TF & ARMII::MO_HI16)
     O << ":upper16:";
+  else if (TF & ARMII::MO_LO_0_7)
+    O << ":lower0_7:";
+  else if (TF & ARMII::MO_LO_8_15)
+    O << ":lower8_15:";
+  else if (TF & ARMII::MO_HI_0_7)
+    O << ":upper0_7:";
+  else if (TF & ARMII::MO_HI_8_15)
+    O << ":upper8_15:";
+
   GetARMGVSymbol(MO.getGlobal(), TF)->print(O, MAI);
   printOffset(MO.getOffset(), O);
 }
@@ -228,6 +237,14 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
       O << ":lower16:";
     else if (TF == ARMII::MO_HI16)
       O << ":upper16:";
+    else if (TF == ARMII::MO_LO_0_7)
+      O << ":lower0_7:";
+    else if (TF == ARMII::MO_LO_8_15)
+      O << ":lower8_15:";
+    else if (TF == ARMII::MO_HI_0_7)
+      O << ":upper0_7:";
+    else if (TF == ARMII::MO_HI_8_15)
+      O << ":upper8_15:";
     O << MO.getImm();
     break;
   }

diff  --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index 2e165f7c25e72..f903d583d7c64 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -3327,7 +3327,8 @@ bool ARMBaseInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
                                      MachineRegisterInfo *MRI) const {
   // Fold large immediates into add, sub, or, xor.
   unsigned DefOpc = DefMI.getOpcode();
-  if (DefOpc != ARM::t2MOVi32imm && DefOpc != ARM::MOVi32imm)
+  if (DefOpc != ARM::t2MOVi32imm && DefOpc != ARM::MOVi32imm &&
+      DefOpc != ARM::tMOVi32imm)
     return false;
   if (!DefMI.getOperand(1).isImm())
     // Could be t2MOVi32imm @xx
@@ -5538,7 +5539,10 @@ ARMBaseInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
   using namespace ARMII;
 
   static const std::pair<unsigned, const char *> TargetFlags[] = {
-      {MO_LO16, "arm-lo16"}, {MO_HI16, "arm-hi16"}};
+      {MO_LO16, "arm-lo16"},       {MO_HI16, "arm-hi16"},
+      {MO_LO_0_7, "arm-lo-0-7"},   {MO_HI_0_7, "arm-hi-0-7"},
+      {MO_LO_8_15, "arm-lo-8-15"}, {MO_HI_8_15, "arm-hi-8-15"},
+  };
   return ArrayRef(TargetFlags);
 }
 

diff  --git a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
index 53c575fb73d9d..0c5f9ac095d0c 100644
--- a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp
@@ -71,6 +71,8 @@ namespace {
     void ExpandVTBL(MachineBasicBlock::iterator &MBBI,
                     unsigned Opc, bool IsExt);
     void ExpandMQQPRLoadStore(MachineBasicBlock::iterator &MBBI);
+    void ExpandTMOV32BitImm(MachineBasicBlock &MBB,
+                            MachineBasicBlock::iterator &MBBI);
     void ExpandMOV32BitImm(MachineBasicBlock &MBB,
                            MachineBasicBlock::iterator &MBBI);
     void CMSEClearGPRegs(MachineBasicBlock &MBB,
@@ -969,6 +971,106 @@ static MachineOperand makeImplicit(const MachineOperand &MO) {
   return NewMO;
 }
 
+void ARMExpandPseudo::ExpandTMOV32BitImm(MachineBasicBlock &MBB,
+                                         MachineBasicBlock::iterator &MBBI) {
+  MachineInstr &MI = *MBBI;
+  Register DstReg = MI.getOperand(0).getReg();
+  bool DstIsDead = MI.getOperand(0).isDead();
+  const MachineOperand &MO = MI.getOperand(1);
+  MachineInstrBuilder Upper8_15, LSL_U8_15, Upper0_7, Lower8_15, Lower0_7;
+  unsigned MIFlags = MI.getFlags();
+
+  LLVM_DEBUG(dbgs() << "Expanding: "; MI.dump());
+
+  Upper8_15 =
+      BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::tMOVi8), DstReg)
+          .addReg(ARM::CPSR, RegState::Kill);
+
+  LSL_U8_15 =
+      BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::tLSLri), DstReg)
+          .addReg(ARM::CPSR, RegState::Kill)
+          .addReg(DstReg)
+          .addImm(8)
+          .add(predOps(ARMCC::AL))
+          .setMIFlags(MIFlags);
+
+  Upper0_7 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::tADDi8), DstReg)
+                 .addReg(ARM::CPSR, RegState::Kill)
+                 .addReg(DstReg);
+
+  MachineInstr *LSL_U0_7 = MBB.getParent()->CloneMachineInstr(LSL_U8_15);
+  MBB.insert(MBBI, LSL_U0_7);
+
+  Lower8_15 =
+      BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::tADDi8), DstReg)
+          .addReg(ARM::CPSR, RegState::Kill)
+          .addReg(DstReg);
+
+  MachineInstr *LSL_L8_15 = MBB.getParent()->CloneMachineInstr(LSL_U8_15);
+  MBB.insert(MBBI, LSL_L8_15);
+
+  Lower0_7 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::tADDi8))
+                 .addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
+                 .addReg(ARM::CPSR, RegState::Kill)
+                 .addReg(DstReg);
+
+  Upper8_15.setMIFlags(MIFlags);
+  Upper0_7.setMIFlags(MIFlags);
+  Lower8_15.setMIFlags(MIFlags);
+  Lower0_7.setMIFlags(MIFlags);
+
+  switch (MO.getType()) {
+  case MachineOperand::MO_Immediate: {
+    unsigned Imm = MO.getImm();
+    unsigned Hi8_15 = (Imm >> 24) & 0xff;
+    unsigned Hi0_7 = (Imm >> 16) & 0xff;
+    unsigned Lo8_15 = (Imm >> 8) & 0xff;
+    unsigned Lo0_7 = Imm & 0xff;
+    Upper8_15 = Upper8_15.addImm(Hi8_15);
+    Upper0_7 = Upper0_7.addImm(Hi0_7);
+    Lower8_15 = Lower8_15.addImm(Lo8_15);
+    Lower0_7 = Lower0_7.addImm(Lo0_7);
+    break;
+  }
+  case MachineOperand::MO_ExternalSymbol: {
+    const char *ES = MO.getSymbolName();
+    unsigned TF = MO.getTargetFlags();
+    Upper8_15 = Upper8_15.addExternalSymbol(ES, TF | ARMII::MO_HI_8_15);
+    Upper0_7 = Upper0_7.addExternalSymbol(ES, TF | ARMII::MO_HI_0_7);
+    Lower8_15 = Lower8_15.addExternalSymbol(ES, TF | ARMII::MO_LO_8_15);
+    Lower0_7 = Lower0_7.addExternalSymbol(ES, TF | ARMII::MO_LO_0_7);
+    break;
+  }
+  default: {
+    const GlobalValue *GV = MO.getGlobal();
+    unsigned TF = MO.getTargetFlags();
+    Upper8_15 =
+        Upper8_15.addGlobalAddress(GV, MO.getOffset(), TF | ARMII::MO_HI_8_15);
+    Upper0_7 =
+        Upper0_7.addGlobalAddress(GV, MO.getOffset(), TF | ARMII::MO_HI_0_7);
+    Lower8_15 =
+        Lower8_15.addGlobalAddress(GV, MO.getOffset(), TF | ARMII::MO_LO_8_15);
+    Lower0_7 =
+        Lower0_7.addGlobalAddress(GV, MO.getOffset(), TF | ARMII::MO_LO_0_7);
+    break;
+  }
+  }
+
+  Upper8_15 = Upper8_15.add(predOps(ARMCC::AL));
+  Upper0_7 = Upper0_7.add(predOps(ARMCC::AL));
+  Lower8_15 = Lower8_15.add(predOps(ARMCC::AL));
+  Lower0_7 = Lower0_7.add(predOps(ARMCC::AL));
+
+  MI.eraseFromParent();
+  LLVM_DEBUG(dbgs() << "To:        "; Upper8_15.getInstr()->dump(););
+  LLVM_DEBUG(dbgs() << "And:       "; LSL_U8_15.getInstr()->dump(););
+  LLVM_DEBUG(dbgs() << "And:       "; Upper0_7.getInstr()->dump(););
+  LLVM_DEBUG(dbgs() << "And:       "; LSL_U0_7->dump(););
+  LLVM_DEBUG(dbgs() << "And:       "; Lower8_15.getInstr()->dump(););
+  LLVM_DEBUG(dbgs() << "And:       "; LSL_L8_15->dump(););
+  LLVM_DEBUG(dbgs() << "And:       "; Lower0_7.getInstr()->dump(););
+}
+
 void ARMExpandPseudo::ExpandMOV32BitImm(MachineBasicBlock &MBB,
                                         MachineBasicBlock::iterator &MBBI) {
   MachineInstr &MI = *MBBI;
@@ -2658,6 +2760,10 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
       ExpandMOV32BitImm(MBB, MBBI);
       return true;
 
+    case ARM::tMOVi32imm:
+      ExpandTMOV32BitImm(MBB, MBBI);
+      return true;
+
     case ARM::SUBS_PC_LR: {
       MachineInstrBuilder MIB =
           BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::SUBri), ARM::PC)

diff  --git a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
index 1c592af3641c0..a0607cb5662ef 100644
--- a/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
+++ b/llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp
@@ -3701,7 +3701,8 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
   case ISD::Constant: {
     unsigned Val = cast<ConstantSDNode>(N)->getZExtValue();
     // If we can't materialize the constant we need to use a literal pool
-    if (ConstantMaterializationCost(Val, Subtarget) > 2) {
+    if (ConstantMaterializationCost(Val, Subtarget) > 2 &&
+        !Subtarget->genExecuteOnly()) {
       SDValue CPIdx = CurDAG->getTargetConstantPool(
           ConstantInt::get(Type::getInt32Ty(*CurDAG->getContext()), Val),
           TLI->getPointerTy(CurDAG->getDataLayout()));

diff  --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 9cde9205335fd..265ad22a0131d 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -3956,9 +3956,12 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
   }
 
   // If we have T2 ops, we can materialize the address directly via movt/movw
-  // pair. This is always cheaper.
-  if (Subtarget->useMovt()) {
-    ++NumMovwMovt;
+  // pair. This is always cheaper. If need to generate Execute Only code, and we
+  // only have Thumb1 available, we can't use a constant pool and are forced to
+  // use immediate relocations.
+  if (Subtarget->useMovt() || Subtarget->genExecuteOnly()) {
+    if (Subtarget->useMovt())
+      ++NumMovwMovt;
     // FIXME: Once remat is capable of dealing with instructions with register
     // operands, expand this into two nodes.
     return DAG.getNode(ARMISD::Wrapper, dl, PtrVT,

diff  --git a/llvm/lib/Target/ARM/ARMInstrThumb.td b/llvm/lib/Target/ARM/ARMInstrThumb.td
index 7849133b4322f..f20e81d5d9f34 100644
--- a/llvm/lib/Target/ARM/ARMInstrThumb.td
+++ b/llvm/lib/Target/ARM/ARMInstrThumb.td
@@ -1603,7 +1603,22 @@ def tLDRLIT_ga_abs : PseudoInst<(outs tGPR:$dst), (ins i32imm:$src),
                                 IIC_iLoad_i,
                                 [(set tGPR:$dst,
                                       (ARMWrapper tglobaladdr:$src))]>,
-                     Requires<[IsThumb, DontUseMovt]>;
+                     Requires<[IsThumb, DontUseMovt, DontGenExecuteOnly]>;
+
+// 32-bit immediate using mov/add with the 4 :lower0_7: to :upper8_15:
+// relocations.
+// This is a single pseudo instruction to make it re-materializable.
+// FIXME: Remove this when we can do generalized remat.
+let isReMaterializable = 1, isMoveImm = 1, Size = 16, hasNoSchedulingInfo = 1 in
+def tMOVi32imm : PseudoInst<(outs rGPR:$dst), (ins i32imm:$src), NoItinerary,
+                            [(set rGPR:$dst, (i32 imm:$src))]>,
+                            Requires<[IsThumb1Only, GenExecuteOnly, DontUseMovt]>;
+
+def : ARMPat<(ARMWrapper  tglobaladdr :$dst), (tMOVi32imm tglobaladdr :$dst)>,
+            Requires<[GenT1ExecuteOnly]>;
+def : ARMPat<(ARMWrapper texternalsym :$dst), (tMOVi32imm texternalsym :$dst)>,
+            Requires<[GenT1ExecuteOnly]>;
+
 
 // TLS globals
 def : Pat<(ARMWrapperPIC tglobaltlsaddr:$addr),

diff  --git a/llvm/lib/Target/ARM/ARMMCInstLower.cpp b/llvm/lib/Target/ARM/ARMMCInstLower.cpp
index a6b68e55e54af..2c2853223ba56 100644
--- a/llvm/lib/Target/ARM/ARMMCInstLower.cpp
+++ b/llvm/lib/Target/ARM/ARMMCInstLower.cpp
@@ -58,6 +58,22 @@ MCOperand ARMAsmPrinter::GetSymbolRef(const MachineOperand &MO,
         MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
     Expr = ARMMCExpr::createUpper16(Expr, OutContext);
     break;
+  case ARMII::MO_LO_0_7:
+    Expr = MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
+    Expr = ARMMCExpr::createLower0_7(Expr, OutContext);
+    break;
+  case ARMII::MO_LO_8_15:
+    Expr = MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
+    Expr = ARMMCExpr::createLower8_15(Expr, OutContext);
+    break;
+  case ARMII::MO_HI_0_7:
+    Expr = MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
+    Expr = ARMMCExpr::createUpper0_7(Expr, OutContext);
+    break;
+  case ARMII::MO_HI_8_15:
+    Expr = MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
+    Expr = ARMMCExpr::createUpper8_15(Expr, OutContext);
+    break;
   }
 
   if (!MO.isJTI() && MO.getOffset())

diff  --git a/llvm/lib/Target/ARM/ARMPredicates.td b/llvm/lib/Target/ARM/ARMPredicates.td
index 2172ea9008517..aca970d900a8d 100644
--- a/llvm/lib/Target/ARM/ARMPredicates.td
+++ b/llvm/lib/Target/ARM/ARMPredicates.td
@@ -224,6 +224,10 @@ let RecomputePerFunction = 1 in {
 }
 
 def GenExecuteOnly : Predicate<"Subtarget->genExecuteOnly()">;
+def DontGenExecuteOnly : Predicate<"!Subtarget->genExecuteOnly()">;
+def GenT1ExecuteOnly : Predicate<"Subtarget->genExecuteOnly() && "
+                                 "Subtarget->isThumb1Only() && "
+                                 "!Subtarget->hasV8MBaselineOps()">;
 
 // Armv8.5-A extensions
 def HasSB            : Predicate<"Subtarget->hasSB()">,

diff  --git a/llvm/lib/Target/ARM/ARMSubtarget.cpp b/llvm/lib/Target/ARM/ARMSubtarget.cpp
index 53c03a6b28d7e..1505e92140508 100644
--- a/llvm/lib/Target/ARM/ARMSubtarget.cpp
+++ b/llvm/lib/Target/ARM/ARMSubtarget.cpp
@@ -187,10 +187,12 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
   // Assert this for now to make the change obvious.
   assert(hasV6T2Ops() || !hasThumb2());
 
-  // Execute only support requires movt support
   if (genExecuteOnly()) {
-    NoMovt = false;
-    assert(hasV8MBaselineOps() && "Cannot generate execute-only code for this target");
+    // Execute only support for >= v8-M Baseline requires movt support
+    if (hasV8MBaselineOps())
+      NoMovt = false;
+    if (!hasV6MOps())
+      report_fatal_error("Cannot generate execute-only code for this target");
   }
 
   // Keep a pointer to static instruction cost data for the specified CPU.

diff  --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h
index f8de0320166a3..1e87085d7bf07 100644
--- a/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h
+++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h
@@ -255,7 +255,7 @@ namespace ARMII {
 
     /// MO_OPTION_MASK - Most flags are mutually exclusive; this mask selects
     /// just that part of the flag set.
-    MO_OPTION_MASK = 0x3,
+    MO_OPTION_MASK = 0xf03,
 
     /// MO_COFFSTUB - On a symbol operand "FOO", this indicates that the
     /// reference is actually to the ".refptr.FOO" symbol.  This is used for
@@ -287,11 +287,27 @@ namespace ARMII {
     /// example).
     MO_NONLAZY = 0x80,
 
-    // It's undefined behaviour if an enum overflows the range between its
-    // smallest and largest values, but since these are |ed together, it can
-    // happen. Put a sentinel in (values of this enum are stored as "unsigned
-    // char").
-    MO_UNUSED_MAXIMUM = 0xff
+    /// MO_LO_0_7 - On a symbol operand, this represents a relocation containing
+    /// bits 0 through 7 of the address. Used only with Thumb1 MOV and ADD
+    // instructions.
+    MO_LO_0_7 = 0x100,
+
+    /// MO_LO_8_15 - On a symbol operand, this represents a relocation
+    /// containing
+    /// bits 8 through 15 of the address. Used only with Thumb1 MOV and ADD
+    // instructions.
+    MO_LO_8_15 = 0x200,
+
+    /// MO_HI_0_7 - On a symbol operand, this represents a relocation containing
+    /// bits 16 through 23 of the address. Used only with Thumb1 MOV and ADD
+    // instructions.
+    MO_HI_0_7 = 0x400,
+
+    /// MO_HI_8_15 - On a symbol operand, this represents a relocation
+    /// containing
+    /// bits 24 through 31 of the address. Used only with Thumb1 MOV and ADD
+    // instructions.
+    MO_HI_8_15 = 0x800
   };
 
   enum {

diff  --git a/llvm/test/CodeGen/ARM/execute-only-section.ll b/llvm/test/CodeGen/ARM/execute-only-section.ll
index 8c7eb0c43767b..bc9e3c0020494 100644
--- a/llvm/test/CodeGen/ARM/execute-only-section.ll
+++ b/llvm/test/CodeGen/ARM/execute-only-section.ll
@@ -1,3 +1,4 @@
+; RUN: llc < %s -mtriple=thumbv6m -mattr=+execute-only %s -o - | FileCheck %s
 ; RUN: llc < %s -mtriple=thumbv7m -mattr=+execute-only %s -o - | FileCheck %s
 ; RUN: llc < %s -mtriple=thumbv8m.base -mattr=+execute-only %s -o - | FileCheck %s
 ; RUN: llc < %s -mtriple=thumbv8m.base -mcpu=cortex-m23 -mattr=+execute-only %s -o - | FileCheck %s

diff  --git a/llvm/test/CodeGen/ARM/execute-only.ll b/llvm/test/CodeGen/ARM/execute-only.ll
index 364c539238c8c..1123efbc11a75 100644
--- a/llvm/test/CodeGen/ARM/execute-only.ll
+++ b/llvm/test/CodeGen/ARM/execute-only.ll
@@ -2,6 +2,7 @@
 ; RUN: llc -mtriple=thumbv8m.base-eabi -mcpu=cortex-m23 -mattr=+execute-only %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-T2BASE %s
 ; RUN: llc -mtriple=thumbv7m-eabi      -mattr=+execute-only %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-T2 %s
 ; RUN: llc -mtriple=thumbv8m.main-eabi -mattr=+execute-only %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-T2 %s
+; RUN: llc -mtriple=thumbv6m-eabi -mattr=+execute-only %s -o - | FileCheck --check-prefix=CHECK-T1 %s
 
 ; CHECK-NOT: {{^ *}}.text{{$}}
 ; CHECK: .section .text,"axy",%progbits,unique,0
@@ -11,7 +12,15 @@
 define i32 @global() minsize {
 ; CHECK-LABEL: global:
 ; CHECK: movw [[GLOBDEST:r[0-9]+]], :lower16:var
-; CHECK: movt [[GLOBDEST]], :upper16:var
+; CHECK-NEXT: movt [[GLOBDEST]], :upper16:var
+; CHECK-T1-LABEL: global:
+; CHECK-T1: movs [[GLOBDEST:r[0-9]+]], :upper8_15:var
+; CHECK-T1-NEXT: lsls [[GLOBDEST]], [[GLOBDEST]], #8
+; CHECK-T1-NEXT: adds [[GLOBDEST]], :upper0_7:var
+; CHECK-T1-NEXT: lsls [[GLOBDEST]], [[GLOBDEST]], #8
+; CHECK-T1-NEXT: adds [[GLOBDEST]], :lower8_15:var
+; CHECK-T1-NEXT: lsls [[GLOBDEST]], [[GLOBDEST]], #8
+; CHECK-T1-NEXT: adds [[GLOBDEST]], :lower0_7:var
 
   %val = load i32, ptr @var
   ret i32 %val
@@ -80,7 +89,35 @@ return:                                           ; preds = %entry, %sw.bb8, %sw
 define hidden ptr @string_literal() {
 entry:
 ; CHECK-LABEL: string_literal:
-; CHECK-NOT: .asciz
-; CHECK: .fnend
+; CHECK: movw [[STRLIT:r[0-9]+]], :lower16:.L.str
+; CHECK-NEXT: movt [[STRLIT]], :upper16:.L.str
+; CHECK-T1-LABEL: string_literal:
+; CHECK-T1: movs [[STRLIT:r[0-9]+]], :upper8_15:.L.str
+; CHECK-T1-NEXT: lsls [[STRLIT]], [[STRLIT]], #8
+; CHECK-T1-NEXT: adds [[STRLIT]], :upper0_7:.L.str
+; CHECK-T1-NEXT: lsls [[STRLIT]], [[STRLIT]], #8
+; CHECK-T1-NEXT: adds [[STRLIT]], :lower8_15:.L.str
+; CHECK-T1-NEXT: lsls [[STRLIT]], [[STRLIT]], #8
+; CHECK-T1-NEXT: adds [[STRLIT]], :lower0_7:.L.str
+
     ret ptr @.str
 }
+
+ at external_global = external global i32
+define i32 @test_external_global() {
+entry:
+; CHECK-LABEL: external_global:
+; CHECK: movw [[EXTGLOB:r[0-9]+]], :lower16:external_global
+; CHECK-NEXT: movt [[EXTGLOB]], :upper16:external_global
+; CHECK-T1-LABEL: external_global:
+; CHECK-T1: movs [[EXTGLOB:r[0-9]+]], :upper8_15:external_global
+; CHECK-T1-NEXT: lsls [[EXTGLOB]], [[EXTGLOB]], #8
+; CHECK-T1-NEXT: adds [[EXTGLOB]], :upper0_7:external_global
+; CHECK-T1-NEXT: lsls [[EXTGLOB]], [[EXTGLOB]], #8
+; CHECK-T1-NEXT: adds [[EXTGLOB]], :lower8_15:external_global
+; CHECK-T1-NEXT: lsls [[EXTGLOB]], [[EXTGLOB]], #8
+; CHECK-T1-NEXT: adds [[EXTGLOB]], :lower0_7:external_global
+
+  %v = load i32, ptr @external_global
+  ret i32 %v
+}


        


More information about the llvm-commits mailing list