Skip to content

Commit 2273741

Browse files
committed
[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, rust-lang#8 adds r3, :upper0_7:foo lsls r3, rust-lang#8 adds r3, :lower8_15:foo lsls r3, rust-lang#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
1 parent 2f7ab29 commit 2273741

12 files changed

+241
-19
lines changed

llvm/lib/Target/ARM/ARMAsmPrinter.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,15 @@ void ARMAsmPrinter::PrintSymbolOperand(const MachineOperand &MO,
199199
O << ":lower16:";
200200
else if (TF & ARMII::MO_HI16)
201201
O << ":upper16:";
202+
else if (TF & ARMII::MO_LO_0_7)
203+
O << ":lower0_7:";
204+
else if (TF & ARMII::MO_LO_8_15)
205+
O << ":lower8_15:";
206+
else if (TF & ARMII::MO_HI_0_7)
207+
O << ":upper0_7:";
208+
else if (TF & ARMII::MO_HI_8_15)
209+
O << ":upper8_15:";
210+
202211
GetARMGVSymbol(MO.getGlobal(), TF)->print(O, MAI);
203212
printOffset(MO.getOffset(), O);
204213
}
@@ -228,6 +237,14 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
228237
O << ":lower16:";
229238
else if (TF == ARMII::MO_HI16)
230239
O << ":upper16:";
240+
else if (TF == ARMII::MO_LO_0_7)
241+
O << ":lower0_7:";
242+
else if (TF == ARMII::MO_LO_8_15)
243+
O << ":lower8_15:";
244+
else if (TF == ARMII::MO_HI_0_7)
245+
O << ":upper0_7:";
246+
else if (TF == ARMII::MO_HI_8_15)
247+
O << ":upper8_15:";
231248
O << MO.getImm();
232249
break;
233250
}

llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -3327,7 +3327,8 @@ bool ARMBaseInstrInfo::FoldImmediate(MachineInstr &UseMI, MachineInstr &DefMI,
33273327
MachineRegisterInfo *MRI) const {
33283328
// Fold large immediates into add, sub, or, xor.
33293329
unsigned DefOpc = DefMI.getOpcode();
3330-
if (DefOpc != ARM::t2MOVi32imm && DefOpc != ARM::MOVi32imm)
3330+
if (DefOpc != ARM::t2MOVi32imm && DefOpc != ARM::MOVi32imm &&
3331+
DefOpc != ARM::tMOVi32imm)
33313332
return false;
33323333
if (!DefMI.getOperand(1).isImm())
33333334
// Could be t2MOVi32imm @xx
@@ -5538,7 +5539,10 @@ ARMBaseInstrInfo::getSerializableDirectMachineOperandTargetFlags() const {
55385539
using namespace ARMII;
55395540

55405541
static const std::pair<unsigned, const char *> TargetFlags[] = {
5541-
{MO_LO16, "arm-lo16"}, {MO_HI16, "arm-hi16"}};
5542+
{MO_LO16, "arm-lo16"}, {MO_HI16, "arm-hi16"},
5543+
{MO_LO_0_7, "arm-lo-0-7"}, {MO_HI_0_7, "arm-hi-0-7"},
5544+
{MO_LO_8_15, "arm-lo-8-15"}, {MO_HI_8_15, "arm-hi-8-15"},
5545+
};
55425546
return ArrayRef(TargetFlags);
55435547
}
55445548

llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp

+106
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ namespace {
7171
void ExpandVTBL(MachineBasicBlock::iterator &MBBI,
7272
unsigned Opc, bool IsExt);
7373
void ExpandMQQPRLoadStore(MachineBasicBlock::iterator &MBBI);
74+
void ExpandTMOV32BitImm(MachineBasicBlock &MBB,
75+
MachineBasicBlock::iterator &MBBI);
7476
void ExpandMOV32BitImm(MachineBasicBlock &MBB,
7577
MachineBasicBlock::iterator &MBBI);
7678
void CMSEClearGPRegs(MachineBasicBlock &MBB,
@@ -969,6 +971,106 @@ static MachineOperand makeImplicit(const MachineOperand &MO) {
969971
return NewMO;
970972
}
971973

974+
void ARMExpandPseudo::ExpandTMOV32BitImm(MachineBasicBlock &MBB,
975+
MachineBasicBlock::iterator &MBBI) {
976+
MachineInstr &MI = *MBBI;
977+
Register DstReg = MI.getOperand(0).getReg();
978+
bool DstIsDead = MI.getOperand(0).isDead();
979+
const MachineOperand &MO = MI.getOperand(1);
980+
MachineInstrBuilder Upper8_15, LSL_U8_15, Upper0_7, Lower8_15, Lower0_7;
981+
unsigned MIFlags = MI.getFlags();
982+
983+
LLVM_DEBUG(dbgs() << "Expanding: "; MI.dump());
984+
985+
Upper8_15 =
986+
BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::tMOVi8), DstReg)
987+
.addReg(ARM::CPSR, RegState::Kill);
988+
989+
LSL_U8_15 =
990+
BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::tLSLri), DstReg)
991+
.addReg(ARM::CPSR, RegState::Kill)
992+
.addReg(DstReg)
993+
.addImm(8)
994+
.add(predOps(ARMCC::AL))
995+
.setMIFlags(MIFlags);
996+
997+
Upper0_7 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::tADDi8), DstReg)
998+
.addReg(ARM::CPSR, RegState::Kill)
999+
.addReg(DstReg);
1000+
1001+
MachineInstr *LSL_U0_7 = MBB.getParent()->CloneMachineInstr(LSL_U8_15);
1002+
MBB.insert(MBBI, LSL_U0_7);
1003+
1004+
Lower8_15 =
1005+
BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::tADDi8), DstReg)
1006+
.addReg(ARM::CPSR, RegState::Kill)
1007+
.addReg(DstReg);
1008+
1009+
MachineInstr *LSL_L8_15 = MBB.getParent()->CloneMachineInstr(LSL_U8_15);
1010+
MBB.insert(MBBI, LSL_L8_15);
1011+
1012+
Lower0_7 = BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::tADDi8))
1013+
.addReg(DstReg, RegState::Define | getDeadRegState(DstIsDead))
1014+
.addReg(ARM::CPSR, RegState::Kill)
1015+
.addReg(DstReg);
1016+
1017+
Upper8_15.setMIFlags(MIFlags);
1018+
Upper0_7.setMIFlags(MIFlags);
1019+
Lower8_15.setMIFlags(MIFlags);
1020+
Lower0_7.setMIFlags(MIFlags);
1021+
1022+
switch (MO.getType()) {
1023+
case MachineOperand::MO_Immediate: {
1024+
unsigned Imm = MO.getImm();
1025+
unsigned Hi8_15 = (Imm >> 24) & 0xff;
1026+
unsigned Hi0_7 = (Imm >> 16) & 0xff;
1027+
unsigned Lo8_15 = (Imm >> 8) & 0xff;
1028+
unsigned Lo0_7 = Imm & 0xff;
1029+
Upper8_15 = Upper8_15.addImm(Hi8_15);
1030+
Upper0_7 = Upper0_7.addImm(Hi0_7);
1031+
Lower8_15 = Lower8_15.addImm(Lo8_15);
1032+
Lower0_7 = Lower0_7.addImm(Lo0_7);
1033+
break;
1034+
}
1035+
case MachineOperand::MO_ExternalSymbol: {
1036+
const char *ES = MO.getSymbolName();
1037+
unsigned TF = MO.getTargetFlags();
1038+
Upper8_15 = Upper8_15.addExternalSymbol(ES, TF | ARMII::MO_HI_8_15);
1039+
Upper0_7 = Upper0_7.addExternalSymbol(ES, TF | ARMII::MO_HI_0_7);
1040+
Lower8_15 = Lower8_15.addExternalSymbol(ES, TF | ARMII::MO_LO_8_15);
1041+
Lower0_7 = Lower0_7.addExternalSymbol(ES, TF | ARMII::MO_LO_0_7);
1042+
break;
1043+
}
1044+
default: {
1045+
const GlobalValue *GV = MO.getGlobal();
1046+
unsigned TF = MO.getTargetFlags();
1047+
Upper8_15 =
1048+
Upper8_15.addGlobalAddress(GV, MO.getOffset(), TF | ARMII::MO_HI_8_15);
1049+
Upper0_7 =
1050+
Upper0_7.addGlobalAddress(GV, MO.getOffset(), TF | ARMII::MO_HI_0_7);
1051+
Lower8_15 =
1052+
Lower8_15.addGlobalAddress(GV, MO.getOffset(), TF | ARMII::MO_LO_8_15);
1053+
Lower0_7 =
1054+
Lower0_7.addGlobalAddress(GV, MO.getOffset(), TF | ARMII::MO_LO_0_7);
1055+
break;
1056+
}
1057+
}
1058+
1059+
Upper8_15 = Upper8_15.add(predOps(ARMCC::AL));
1060+
Upper0_7 = Upper0_7.add(predOps(ARMCC::AL));
1061+
Lower8_15 = Lower8_15.add(predOps(ARMCC::AL));
1062+
Lower0_7 = Lower0_7.add(predOps(ARMCC::AL));
1063+
1064+
MI.eraseFromParent();
1065+
LLVM_DEBUG(dbgs() << "To: "; Upper8_15.getInstr()->dump(););
1066+
LLVM_DEBUG(dbgs() << "And: "; LSL_U8_15.getInstr()->dump(););
1067+
LLVM_DEBUG(dbgs() << "And: "; Upper0_7.getInstr()->dump(););
1068+
LLVM_DEBUG(dbgs() << "And: "; LSL_U0_7->dump(););
1069+
LLVM_DEBUG(dbgs() << "And: "; Lower8_15.getInstr()->dump(););
1070+
LLVM_DEBUG(dbgs() << "And: "; LSL_L8_15->dump(););
1071+
LLVM_DEBUG(dbgs() << "And: "; Lower0_7.getInstr()->dump(););
1072+
}
1073+
9721074
void ARMExpandPseudo::ExpandMOV32BitImm(MachineBasicBlock &MBB,
9731075
MachineBasicBlock::iterator &MBBI) {
9741076
MachineInstr &MI = *MBBI;
@@ -2658,6 +2760,10 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
26582760
ExpandMOV32BitImm(MBB, MBBI);
26592761
return true;
26602762

2763+
case ARM::tMOVi32imm:
2764+
ExpandTMOV32BitImm(MBB, MBBI);
2765+
return true;
2766+
26612767
case ARM::SUBS_PC_LR: {
26622768
MachineInstrBuilder MIB =
26632769
BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(ARM::SUBri), ARM::PC)

llvm/lib/Target/ARM/ARMISelDAGToDAG.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -3701,7 +3701,8 @@ void ARMDAGToDAGISel::Select(SDNode *N) {
37013701
case ISD::Constant: {
37023702
unsigned Val = cast<ConstantSDNode>(N)->getZExtValue();
37033703
// If we can't materialize the constant we need to use a literal pool
3704-
if (ConstantMaterializationCost(Val, Subtarget) > 2) {
3704+
if (ConstantMaterializationCost(Val, Subtarget) > 2 &&
3705+
!Subtarget->genExecuteOnly()) {
37053706
SDValue CPIdx = CurDAG->getTargetConstantPool(
37063707
ConstantInt::get(Type::getInt32Ty(*CurDAG->getContext()), Val),
37073708
TLI->getPointerTy(CurDAG->getDataLayout()));

llvm/lib/Target/ARM/ARMISelLowering.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -3956,9 +3956,12 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
39563956
}
39573957

39583958
// If we have T2 ops, we can materialize the address directly via movt/movw
3959-
// pair. This is always cheaper.
3960-
if (Subtarget->useMovt()) {
3961-
++NumMovwMovt;
3959+
// pair. This is always cheaper. If need to generate Execute Only code, and we
3960+
// only have Thumb1 available, we can't use a constant pool and are forced to
3961+
// use immediate relocations.
3962+
if (Subtarget->useMovt() || Subtarget->genExecuteOnly()) {
3963+
if (Subtarget->useMovt())
3964+
++NumMovwMovt;
39623965
// FIXME: Once remat is capable of dealing with instructions with register
39633966
// operands, expand this into two nodes.
39643967
return DAG.getNode(ARMISD::Wrapper, dl, PtrVT,

llvm/lib/Target/ARM/ARMInstrThumb.td

+16-1
Original file line numberDiff line numberDiff line change
@@ -1603,7 +1603,22 @@ def tLDRLIT_ga_abs : PseudoInst<(outs tGPR:$dst), (ins i32imm:$src),
16031603
IIC_iLoad_i,
16041604
[(set tGPR:$dst,
16051605
(ARMWrapper tglobaladdr:$src))]>,
1606-
Requires<[IsThumb, DontUseMovt]>;
1606+
Requires<[IsThumb, DontUseMovt, DontGenExecuteOnly]>;
1607+
1608+
// 32-bit immediate using mov/add with the 4 :lower0_7: to :upper8_15:
1609+
// relocations.
1610+
// This is a single pseudo instruction to make it re-materializable.
1611+
// FIXME: Remove this when we can do generalized remat.
1612+
let isReMaterializable = 1, isMoveImm = 1, Size = 16, hasNoSchedulingInfo = 1 in
1613+
def tMOVi32imm : PseudoInst<(outs rGPR:$dst), (ins i32imm:$src), NoItinerary,
1614+
[(set rGPR:$dst, (i32 imm:$src))]>,
1615+
Requires<[IsThumb1Only, GenExecuteOnly, DontUseMovt]>;
1616+
1617+
def : ARMPat<(ARMWrapper tglobaladdr :$dst), (tMOVi32imm tglobaladdr :$dst)>,
1618+
Requires<[GenT1ExecuteOnly]>;
1619+
def : ARMPat<(ARMWrapper texternalsym :$dst), (tMOVi32imm texternalsym :$dst)>,
1620+
Requires<[GenT1ExecuteOnly]>;
1621+
16071622

16081623
// TLS globals
16091624
def : Pat<(ARMWrapperPIC tglobaltlsaddr:$addr),

llvm/lib/Target/ARM/ARMMCInstLower.cpp

+16
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,22 @@ MCOperand ARMAsmPrinter::GetSymbolRef(const MachineOperand &MO,
5858
MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
5959
Expr = ARMMCExpr::createUpper16(Expr, OutContext);
6060
break;
61+
case ARMII::MO_LO_0_7:
62+
Expr = MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
63+
Expr = ARMMCExpr::createLower0_7(Expr, OutContext);
64+
break;
65+
case ARMII::MO_LO_8_15:
66+
Expr = MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
67+
Expr = ARMMCExpr::createLower8_15(Expr, OutContext);
68+
break;
69+
case ARMII::MO_HI_0_7:
70+
Expr = MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
71+
Expr = ARMMCExpr::createUpper0_7(Expr, OutContext);
72+
break;
73+
case ARMII::MO_HI_8_15:
74+
Expr = MCSymbolRefExpr::create(Symbol, SymbolVariant, OutContext);
75+
Expr = ARMMCExpr::createUpper8_15(Expr, OutContext);
76+
break;
6177
}
6278

6379
if (!MO.isJTI() && MO.getOffset())

llvm/lib/Target/ARM/ARMPredicates.td

+4
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,10 @@ let RecomputePerFunction = 1 in {
224224
}
225225

226226
def GenExecuteOnly : Predicate<"Subtarget->genExecuteOnly()">;
227+
def DontGenExecuteOnly : Predicate<"!Subtarget->genExecuteOnly()">;
228+
def GenT1ExecuteOnly : Predicate<"Subtarget->genExecuteOnly() && "
229+
"Subtarget->isThumb1Only() && "
230+
"!Subtarget->hasV8MBaselineOps()">;
227231

228232
// Armv8.5-A extensions
229233
def HasSB : Predicate<"Subtarget->hasSB()">,

llvm/lib/Target/ARM/ARMSubtarget.cpp

+5-3
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,12 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
187187
// Assert this for now to make the change obvious.
188188
assert(hasV6T2Ops() || !hasThumb2());
189189

190-
// Execute only support requires movt support
191190
if (genExecuteOnly()) {
192-
NoMovt = false;
193-
assert(hasV8MBaselineOps() && "Cannot generate execute-only code for this target");
191+
// Execute only support for >= v8-M Baseline requires movt support
192+
if (hasV8MBaselineOps())
193+
NoMovt = false;
194+
if (!hasV6MOps())
195+
report_fatal_error("Cannot generate execute-only code for this target");
194196
}
195197

196198
// Keep a pointer to static instruction cost data for the specified CPU.

llvm/lib/Target/ARM/MCTargetDesc/ARMBaseInfo.h

+22-6
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ namespace ARMII {
255255

256256
/// MO_OPTION_MASK - Most flags are mutually exclusive; this mask selects
257257
/// just that part of the flag set.
258-
MO_OPTION_MASK = 0x3,
258+
MO_OPTION_MASK = 0xf03,
259259

260260
/// MO_COFFSTUB - On a symbol operand "FOO", this indicates that the
261261
/// reference is actually to the ".refptr.FOO" symbol. This is used for
@@ -287,11 +287,27 @@ namespace ARMII {
287287
/// example).
288288
MO_NONLAZY = 0x80,
289289

290-
// It's undefined behaviour if an enum overflows the range between its
291-
// smallest and largest values, but since these are |ed together, it can
292-
// happen. Put a sentinel in (values of this enum are stored as "unsigned
293-
// char").
294-
MO_UNUSED_MAXIMUM = 0xff
290+
/// MO_LO_0_7 - On a symbol operand, this represents a relocation containing
291+
/// bits 0 through 7 of the address. Used only with Thumb1 MOV and ADD
292+
// instructions.
293+
MO_LO_0_7 = 0x100,
294+
295+
/// MO_LO_8_15 - On a symbol operand, this represents a relocation
296+
/// containing
297+
/// bits 8 through 15 of the address. Used only with Thumb1 MOV and ADD
298+
// instructions.
299+
MO_LO_8_15 = 0x200,
300+
301+
/// MO_HI_0_7 - On a symbol operand, this represents a relocation containing
302+
/// bits 16 through 23 of the address. Used only with Thumb1 MOV and ADD
303+
// instructions.
304+
MO_HI_0_7 = 0x400,
305+
306+
/// MO_HI_8_15 - On a symbol operand, this represents a relocation
307+
/// containing
308+
/// bits 24 through 31 of the address. Used only with Thumb1 MOV and ADD
309+
// instructions.
310+
MO_HI_8_15 = 0x800
295311
};
296312

297313
enum {

llvm/test/CodeGen/ARM/execute-only-section.ll

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
; RUN: llc < %s -mtriple=thumbv6m -mattr=+execute-only %s -o - | FileCheck %s
12
; RUN: llc < %s -mtriple=thumbv7m -mattr=+execute-only %s -o - | FileCheck %s
23
; RUN: llc < %s -mtriple=thumbv8m.base -mattr=+execute-only %s -o - | FileCheck %s
34
; RUN: llc < %s -mtriple=thumbv8m.base -mcpu=cortex-m23 -mattr=+execute-only %s -o - | FileCheck %s

llvm/test/CodeGen/ARM/execute-only.ll

+40-3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
; RUN: llc -mtriple=thumbv8m.base-eabi -mcpu=cortex-m23 -mattr=+execute-only %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-T2BASE %s
33
; RUN: llc -mtriple=thumbv7m-eabi -mattr=+execute-only %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-T2 %s
44
; RUN: llc -mtriple=thumbv8m.main-eabi -mattr=+execute-only %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-T2 %s
5+
; RUN: llc -mtriple=thumbv6m-eabi -mattr=+execute-only %s -o - | FileCheck --check-prefix=CHECK-T1 %s
56

67
; CHECK-NOT: {{^ *}}.text{{$}}
78
; CHECK: .section .text,"axy",%progbits,unique,0
@@ -11,7 +12,15 @@
1112
define i32 @global() minsize {
1213
; CHECK-LABEL: global:
1314
; CHECK: movw [[GLOBDEST:r[0-9]+]], :lower16:var
14-
; CHECK: movt [[GLOBDEST]], :upper16:var
15+
; CHECK-NEXT: movt [[GLOBDEST]], :upper16:var
16+
; CHECK-T1-LABEL: global:
17+
; CHECK-T1: movs [[GLOBDEST:r[0-9]+]], :upper8_15:var
18+
; CHECK-T1-NEXT: lsls [[GLOBDEST]], [[GLOBDEST]], #8
19+
; CHECK-T1-NEXT: adds [[GLOBDEST]], :upper0_7:var
20+
; CHECK-T1-NEXT: lsls [[GLOBDEST]], [[GLOBDEST]], #8
21+
; CHECK-T1-NEXT: adds [[GLOBDEST]], :lower8_15:var
22+
; CHECK-T1-NEXT: lsls [[GLOBDEST]], [[GLOBDEST]], #8
23+
; CHECK-T1-NEXT: adds [[GLOBDEST]], :lower0_7:var
1524

1625
%val = load i32, ptr @var
1726
ret i32 %val
@@ -80,7 +89,35 @@ return: ; preds = %entry, %sw.bb8, %sw
8089
define hidden ptr @string_literal() {
8190
entry:
8291
; CHECK-LABEL: string_literal:
83-
; CHECK-NOT: .asciz
84-
; CHECK: .fnend
92+
; CHECK: movw [[STRLIT:r[0-9]+]], :lower16:.L.str
93+
; CHECK-NEXT: movt [[STRLIT]], :upper16:.L.str
94+
; CHECK-T1-LABEL: string_literal:
95+
; CHECK-T1: movs [[STRLIT:r[0-9]+]], :upper8_15:.L.str
96+
; CHECK-T1-NEXT: lsls [[STRLIT]], [[STRLIT]], #8
97+
; CHECK-T1-NEXT: adds [[STRLIT]], :upper0_7:.L.str
98+
; CHECK-T1-NEXT: lsls [[STRLIT]], [[STRLIT]], #8
99+
; CHECK-T1-NEXT: adds [[STRLIT]], :lower8_15:.L.str
100+
; CHECK-T1-NEXT: lsls [[STRLIT]], [[STRLIT]], #8
101+
; CHECK-T1-NEXT: adds [[STRLIT]], :lower0_7:.L.str
102+
85103
ret ptr @.str
86104
}
105+
106+
@external_global = external global i32
107+
define i32 @test_external_global() {
108+
entry:
109+
; CHECK-LABEL: external_global:
110+
; CHECK: movw [[EXTGLOB:r[0-9]+]], :lower16:external_global
111+
; CHECK-NEXT: movt [[EXTGLOB]], :upper16:external_global
112+
; CHECK-T1-LABEL: external_global:
113+
; CHECK-T1: movs [[EXTGLOB:r[0-9]+]], :upper8_15:external_global
114+
; CHECK-T1-NEXT: lsls [[EXTGLOB]], [[EXTGLOB]], #8
115+
; CHECK-T1-NEXT: adds [[EXTGLOB]], :upper0_7:external_global
116+
; CHECK-T1-NEXT: lsls [[EXTGLOB]], [[EXTGLOB]], #8
117+
; CHECK-T1-NEXT: adds [[EXTGLOB]], :lower8_15:external_global
118+
; CHECK-T1-NEXT: lsls [[EXTGLOB]], [[EXTGLOB]], #8
119+
; CHECK-T1-NEXT: adds [[EXTGLOB]], :lower0_7:external_global
120+
121+
%v = load i32, ptr @external_global
122+
ret i32 %v
123+
}

0 commit comments

Comments
 (0)