Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit af672fb

Browse files
author
Prakhar Bahuguna
committed
[ARM] Implement execute-only support in CodeGen
This implements execute-only support for ARM code generation, which prevents the compiler from generating data accesses to code sections. The following changes are involved: * Add the CodeGen option "-arm-execute-only" to the ARM code generator. * Add the clang flag "-mexecute-only" as well as the GCC-compatible alias "-mpure-code" to enable this option. * When enabled, literal pools are replaced with MOVW/MOVT instructions, with VMOV used in addition for floating-point literals. As the MOVT instruction is required, execute-only support is only available in Thumb mode for targets supporting ARMv8-M baseline or Thumb2. * Jump tables are placed in data sections when in execute-only mode. * The execute-only text section is assigned section ID 0, and is marked as unreadable with the SHF_ARM_PURECODE flag with symbol 'y'. This also overrides selection of ELF sections for globals. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@289784 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent a1b0287 commit af672fb

27 files changed

+455
-20
lines changed

include/llvm/CodeGen/TargetLoweringObjectFileImpl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ namespace llvm {
3333

3434
class TargetLoweringObjectFileELF : public TargetLoweringObjectFile {
3535
bool UseInitArray;
36-
mutable unsigned NextUniqueID = 0;
36+
mutable unsigned NextUniqueID = 1; // ID 0 is reserved for execute-only sections
3737

3838
protected:
3939
MCSymbolRefExpr::VariantKind PLTRelativeVariantKind =

include/llvm/MC/SectionKind.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ class SectionKind {
2828
/// Text - Text section, used for functions and other executable code.
2929
Text,
3030

31+
/// ExecuteOnly, Text section that is not readable.
32+
ExecuteOnly,
33+
3134
/// ReadOnly - Data that is never written to at program runtime by the
3235
/// program or the dynamic linker. Things in the top-level readonly
3336
/// SectionKind are not mergeable.
@@ -112,7 +115,10 @@ class SectionKind {
112115
public:
113116

114117
bool isMetadata() const { return K == Metadata; }
115-
bool isText() const { return K == Text; }
118+
119+
bool isText() const { return K == Text || K == ExecuteOnly; }
120+
121+
bool isExecuteOnly() const { return K == ExecuteOnly; }
116122

117123
bool isReadOnly() const {
118124
return K == ReadOnly || isMergeableCString() ||
@@ -172,6 +178,7 @@ class SectionKind {
172178

173179
static SectionKind getMetadata() { return get(Metadata); }
174180
static SectionKind getText() { return get(Text); }
181+
static SectionKind getExecuteOnly() { return get(ExecuteOnly); }
175182
static SectionKind getReadOnly() { return get(ReadOnly); }
176183
static SectionKind getMergeable1ByteCString() {
177184
return get(Mergeable1ByteCString);

include/llvm/Support/ELF.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,9 @@ enum : unsigned {
804804
// Section data is string data by default.
805805
SHF_MIPS_STRING = 0x80000000,
806806

807+
// Make code section unreadable when in execute-only mode
808+
SHF_ARM_PURECODE = 0x20000000,
809+
807810
SHF_AMDGPU_HSA_GLOBAL = 0x00100000,
808811
SHF_AMDGPU_HSA_READONLY = 0x00200000,
809812
SHF_AMDGPU_HSA_CODE = 0x00400000,

lib/CodeGen/TargetLoweringObjectFileImpl.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ static unsigned getELFSectionFlags(SectionKind K) {
181181
if (K.isText())
182182
Flags |= ELF::SHF_EXECINSTR;
183183

184+
if (K.isExecuteOnly())
185+
Flags |= ELF::SHF_ARM_PURECODE;
186+
184187
if (K.isWriteable())
185188
Flags |= ELF::SHF_WRITE;
186189

@@ -312,6 +315,9 @@ selectELFSectionForGlobal(MCContext &Ctx, const GlobalObject *GO,
312315
UniqueID = *NextUniqueID;
313316
(*NextUniqueID)++;
314317
}
318+
// Use 0 as the unique ID for execute-only text
319+
if (Kind.isExecuteOnly())
320+
UniqueID = 0;
315321
return Ctx.getELFSection(Name, getELFSectionType(Name, Kind), Flags,
316322
EntrySize, Group, UniqueID);
317323
}

lib/MC/MCContext.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,9 @@ MCSectionELF *MCContext::getELFSection(const Twine &Section, unsigned Type,
368368
StringRef CachedName = Entry.first.SectionName;
369369

370370
SectionKind Kind;
371-
if (Flags & ELF::SHF_EXECINSTR)
371+
if (Flags & ELF::SHF_ARM_PURECODE)
372+
Kind = SectionKind::getExecuteOnly();
373+
else if (Flags & ELF::SHF_EXECINSTR)
372374
Kind = SectionKind::getText();
373375
else
374376
Kind = SectionKind::getReadOnly();

lib/MC/MCParser/ELFAsmParser.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,9 @@ static unsigned parseSectionFlags(StringRef flagsStr, bool *UseLastGroup) {
293293
case 'd':
294294
flags |= ELF::XCORE_SHF_DP_SECTION;
295295
break;
296+
case 'y':
297+
flags |= ELF::SHF_ARM_PURECODE;
298+
break;
296299
case 'G':
297300
flags |= ELF::SHF_GROUP;
298301
break;

lib/MC/MCSectionELF.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI,
110110
OS << 'c';
111111
if (Flags & ELF::XCORE_SHF_DP_SECTION)
112112
OS << 'd';
113+
if (Flags & ELF::SHF_ARM_PURECODE)
114+
OS << 'y';
113115

114116
OS << '"';
115117

lib/ObjectYAML/ELFYAML.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,9 @@ void ScalarBitSetTraits<ELFYAML::ELF_SHF>::bitset(IO &IO,
423423
BCase(SHF_GROUP)
424424
BCase(SHF_TLS)
425425
switch(Object->Header.Machine) {
426+
case ELF::EM_ARM:
427+
BCase(SHF_ARM_PURECODE)
428+
break;
426429
case ELF::EM_AMDGPU:
427430
BCase(SHF_AMDGPU_HSA_GLOBAL)
428431
BCase(SHF_AMDGPU_HSA_READONLY)

lib/Target/ARM/ARMAsmPrinter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ void ARMAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,
232232
break;
233233
}
234234
case MachineOperand::MO_ConstantPoolIndex:
235+
if (Subtarget->genExecuteOnly())
236+
llvm_unreachable("execute-only should not generate constant pools");
235237
GetCPISymbol(MO.getIndex())->print(O, MAI);
236238
break;
237239
}

lib/Target/ARM/ARMConstantIslandPass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ bool ARMConstantIslands::runOnMachineFunction(MachineFunction &mf) {
423423
MadeChange |= optimizeThumb2Branches();
424424

425425
// Optimize jump tables using TBB / TBH.
426-
if (GenerateTBB)
426+
if (GenerateTBB && !STI->genExecuteOnly())
427427
MadeChange |= optimizeThumb2JumpTables();
428428

429429
// After a while, this might be made debug-only, but it is not expensive.

lib/Target/ARM/ARMISelLowering.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3152,7 +3152,8 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
31523152
(isa<GlobalVariable>(GV) && cast<GlobalVariable>(GV)->isConstant()) ||
31533153
isa<Function>(GV);
31543154

3155-
if (TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
3155+
// promoteToConstantPool only if not generating XO text section
3156+
if (TM.shouldAssumeDSOLocal(*GV->getParent(), GV) && !Subtarget->genExecuteOnly())
31563157
if (SDValue V = promoteToConstantPool(GV, DAG, PtrVT, dl))
31573158
return V;
31583159

@@ -4492,10 +4493,10 @@ SDValue ARMTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const {
44924493
Table = DAG.getNode(ARMISD::WrapperJT, dl, MVT::i32, JTI);
44934494
Index = DAG.getNode(ISD::MUL, dl, PTy, Index, DAG.getConstant(4, dl, PTy));
44944495
SDValue Addr = DAG.getNode(ISD::ADD, dl, PTy, Index, Table);
4495-
if (Subtarget->isThumb2()) {
4496-
// Thumb2 uses a two-level jump. That is, it jumps into the jump table
4496+
if (Subtarget->isThumb2() || (Subtarget->hasV8MBaselineOps() && Subtarget->isThumb())) {
4497+
// Thumb2 and ARMv8-M use a two-level jump. That is, it jumps into the jump table
44974498
// which does another jump to the destination. This also makes it easier
4498-
// to translate it to TBB / TBH later.
4499+
// to translate it to TBB / TBH later (Thumb2 only).
44994500
// FIXME: This might not work if the function is extremely large.
45004501
return DAG.getNode(ARMISD::BR2_JT, dl, MVT::Other, Chain,
45014502
Addr, Op.getOperand(2), JTI);
@@ -5571,19 +5572,35 @@ static SDValue isNEONModifiedImm(uint64_t SplatBits, uint64_t SplatUndef,
55715572

55725573
SDValue ARMTargetLowering::LowerConstantFP(SDValue Op, SelectionDAG &DAG,
55735574
const ARMSubtarget *ST) const {
5574-
if (!ST->hasVFP3())
5575-
return SDValue();
5576-
55775575
bool IsDouble = Op.getValueType() == MVT::f64;
55785576
ConstantFPSDNode *CFP = cast<ConstantFPSDNode>(Op);
5577+
const APFloat &FPVal = CFP->getValueAPF();
5578+
5579+
// Prevent floating-point constants from using literal loads
5580+
// when execute-only is enabled.
5581+
if (ST->genExecuteOnly()) {
5582+
APInt INTVal = FPVal.bitcastToAPInt();
5583+
SDLoc DL(CFP);
5584+
if (IsDouble) {
5585+
SDValue Lo = DAG.getConstant(INTVal.trunc(32), DL, MVT::i32);
5586+
SDValue Hi = DAG.getConstant(INTVal.lshr(32).trunc(32), DL, MVT::i32);
5587+
if (!ST->isLittle())
5588+
std::swap(Lo, Hi);
5589+
return DAG.getNode(ARMISD::VMOVDRR, DL, MVT::f64, Lo, Hi);
5590+
} else {
5591+
return DAG.getConstant(INTVal, DL, MVT::i32);
5592+
}
5593+
}
5594+
5595+
if (!ST->hasVFP3())
5596+
return SDValue();
55795597

55805598
// Use the default (constant pool) lowering for double constants when we have
55815599
// an SP-only FPU
55825600
if (IsDouble && Subtarget->isFPOnlySP())
55835601
return SDValue();
55845602

55855603
// Try splatting with a VMOV.f32...
5586-
const APFloat &FPVal = CFP->getValueAPF();
55875604
int ImmVal = IsDouble ? ARM_AM::getFP64Imm(FPVal) : ARM_AM::getFP32Imm(FPVal);
55885605

55895606
if (ImmVal != -1) {
@@ -7617,7 +7634,10 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
76177634
switch (Op.getOpcode()) {
76187635
default: llvm_unreachable("Don't know how to custom lower this!");
76197636
case ISD::WRITE_REGISTER: return LowerWRITE_REGISTER(Op, DAG);
7620-
case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
7637+
case ISD::ConstantPool:
7638+
if (Subtarget->genExecuteOnly())
7639+
llvm_unreachable("execute-only should not generate constant pools");
7640+
return LowerConstantPool(Op, DAG);
76217641
case ISD::BlockAddress: return LowerBlockAddress(Op, DAG);
76227642
case ISD::GlobalAddress:
76237643
switch (Subtarget->getTargetTriple().getObjectFormat()) {

lib/Target/ARM/ARMInstrFormats.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,14 @@ class tPseudoInst<dag oops, dag iops, int sz, InstrItinClass itin,
398398
list<Predicate> Predicates = [IsThumb];
399399
}
400400

401+
// PseudoInst that's in ARMv8-M baseline (Somewhere between Thumb and Thumb2)
402+
class t2basePseudoInst<dag oops, dag iops, int sz, InstrItinClass itin,
403+
list<dag> pattern>
404+
: PseudoInst<oops, iops, itin, pattern> {
405+
let Size = sz;
406+
list<Predicate> Predicates = [IsThumb,HasV8MBaseline];
407+
}
408+
401409
// PseudoInst that's Thumb2-mode only.
402410
class t2PseudoInst<dag oops, dag iops, int sz, InstrItinClass itin,
403411
list<dag> pattern>

lib/Target/ARM/ARMInstrInfo.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,8 @@ def DontUseVMOVSR : Predicate<"!Subtarget->preferVMOVSR() &&"
330330
def IsLE : Predicate<"MF->getDataLayout().isLittleEndian()">;
331331
def IsBE : Predicate<"MF->getDataLayout().isBigEndian()">;
332332

333+
def GenExecuteOnly : Predicate<"Subtarget->genExecuteOnly()">;
334+
333335
//===----------------------------------------------------------------------===//
334336
// ARM Flag Definitions.
335337

lib/Target/ARM/ARMInstrThumb2.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3381,7 +3381,9 @@ def t2B : T2I<(outs), (ins thumb_br_target:$target), IIC_Br,
33813381
}
33823382

33833383
let Size = 4, isNotDuplicable = 1, isIndirectBranch = 1 in {
3384-
def t2BR_JT : t2PseudoInst<(outs),
3384+
3385+
// available in both v8-M.Baseline and Thumb2 targets
3386+
def t2BR_JT : t2basePseudoInst<(outs),
33853387
(ins GPR:$target, GPR:$index, i32imm:$jt),
33863388
0, IIC_Br,
33873389
[(ARMbr2jt GPR:$target, GPR:$index, tjumptable:$jt)]>,

lib/Target/ARM/ARMMCInstLower.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ bool ARMAsmPrinter::lowerOperand(const MachineOperand &MO,
9191
MCOp = GetSymbolRef(MO, GetJTISymbol(MO.getIndex()));
9292
break;
9393
case MachineOperand::MO_ConstantPoolIndex:
94+
if (Subtarget->genExecuteOnly())
95+
llvm_unreachable("execute-only should not generate constant pools");
9496
MCOp = GetSymbolRef(MO, GetCPISymbol(MO.getIndex()));
9597
break;
9698
case MachineOperand::MO_BlockAddress:

lib/Target/ARM/ARMSubtarget.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ ARMSubtarget &ARMSubtarget::initializeSubtargetDependencies(StringRef CPU,
7676
return *this;
7777
}
7878

79+
/// EnableExecuteOnly - Enables the generation of execute-only code on supported
80+
/// targets
81+
static cl::opt<bool>
82+
EnableExecuteOnly("arm-execute-only");
83+
7984
ARMFrameLowering *ARMSubtarget::initializeFrameLowering(StringRef CPU,
8085
StringRef FS) {
8186
ARMSubtarget &STI = initializeSubtargetDependencies(CPU, FS);
@@ -90,7 +95,8 @@ ARMSubtarget::ARMSubtarget(const Triple &TT, const std::string &CPU,
9095
const ARMBaseTargetMachine &TM, bool IsLittle)
9196
: ARMGenSubtargetInfo(TT, CPU, FS), UseMulOps(UseFusedMulOps),
9297
CPUString(CPU), IsLittle(IsLittle), TargetTriple(TT), Options(TM.Options),
93-
TM(TM), FrameLowering(initializeFrameLowering(CPU, FS)),
98+
TM(TM), GenExecuteOnly(EnableExecuteOnly),
99+
FrameLowering(initializeFrameLowering(CPU, FS)),
94100
// At this point initializeSubtargetDependencies has been called so
95101
// we can query directly.
96102
InstrInfo(isThumb1Only()
@@ -169,6 +175,10 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
169175
// Assert this for now to make the change obvious.
170176
assert(hasV6T2Ops() || !hasThumb2());
171177

178+
// Execute only support requires movt support
179+
if (genExecuteOnly())
180+
assert(hasV8MBaselineOps() && !NoMovt && "Cannot generate execute-only code for this target");
181+
172182
// Keep a pointer to static instruction cost data for the specified CPU.
173183
SchedModel = getSchedModelForCPU(CPUString);
174184

@@ -353,7 +363,7 @@ bool ARMSubtarget::useMovt(const MachineFunction &MF) const {
353363
// immediates as it is inherently position independent, and may be out of
354364
// range otherwise.
355365
return !NoMovt && hasV8MBaselineOps() &&
356-
(isTargetWindows() || !MF.getFunction()->optForMinSize());
366+
(isTargetWindows() || !MF.getFunction()->optForMinSize() || genExecuteOnly());
357367
}
358368

359369
bool ARMSubtarget::useFastISel() const {

lib/Target/ARM/ARMSubtarget.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,9 @@ class ARMSubtarget : public ARMGenSubtargetInfo {
301301
/// Generate calls via indirect call instructions.
302302
bool GenLongCalls = false;
303303

304+
/// Generate code that does not contain data access to code sections.
305+
bool GenExecuteOnly = false;
306+
304307
/// Target machine allowed unsafe FP math (such as use of NEON fp)
305308
bool UnsafeFPMath = false;
306309

@@ -494,6 +497,7 @@ class ARMSubtarget : public ARMGenSubtargetInfo {
494497
bool useNaClTrap() const { return UseNaClTrap; }
495498
bool useSjLjEH() const { return UseSjLjEH; }
496499
bool genLongCalls() const { return GenLongCalls; }
500+
bool genExecuteOnly() const { return GenExecuteOnly; }
497501

498502
bool hasFP16() const { return HasFP16; }
499503
bool hasD16() const { return HasD16; }

lib/Target/ARM/ARMTargetObjectFile.cpp

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ using namespace dwarf;
2727

2828
void ARMElfTargetObjectFile::Initialize(MCContext &Ctx,
2929
const TargetMachine &TM) {
30-
bool isAAPCS_ABI = static_cast<const ARMTargetMachine &>(TM).TargetABI ==
31-
ARMTargetMachine::ARMABI::ARM_ABI_AAPCS;
30+
const ARMTargetMachine &ARM_TM = static_cast<const ARMTargetMachine &>(TM);
31+
bool isAAPCS_ABI = ARM_TM.TargetABI == ARMTargetMachine::ARMABI::ARM_ABI_AAPCS;
32+
genExecuteOnly = ARM_TM.getSubtargetImpl()->genExecuteOnly();
33+
3234
TargetLoweringObjectFileELF::Initialize(Ctx, TM);
3335
InitializeELF(isAAPCS_ABI);
3436

@@ -38,6 +40,16 @@ void ARMElfTargetObjectFile::Initialize(MCContext &Ctx,
3840

3941
AttributesSection =
4042
getContext().getELFSection(".ARM.attributes", ELF::SHT_ARM_ATTRIBUTES, 0);
43+
44+
// Make code section unreadable when in execute-only mode
45+
if (genExecuteOnly) {
46+
unsigned Type = ELF::SHT_PROGBITS;
47+
unsigned Flags = ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_ARM_PURECODE;
48+
// Since we cannot modify flags for an existing section, we create a new
49+
// section with the right flags, and use 0 as the unique ID for
50+
// execute-only text
51+
TextSection = Ctx.getELFSection(".text", Type, Flags, 0, "", 0U);
52+
}
4153
}
4254

4355
const MCExpr *ARMElfTargetObjectFile::getTTypeGlobalReference(
@@ -58,3 +70,23 @@ getDebugThreadLocalSymbol(const MCSymbol *Sym) const {
5870
return MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_ARM_TLSLDO,
5971
getContext());
6072
}
73+
74+
MCSection *
75+
ARMElfTargetObjectFile::getExplicitSectionGlobal(const GlobalObject *GO,
76+
SectionKind SK, const TargetMachine &TM) const {
77+
// Set execute-only access for the explicit section
78+
if (genExecuteOnly && SK.isText())
79+
SK = SectionKind::getExecuteOnly();
80+
81+
return TargetLoweringObjectFileELF::getExplicitSectionGlobal(GO, SK, TM);
82+
}
83+
84+
MCSection *
85+
ARMElfTargetObjectFile::SelectSectionForGlobal(const GlobalObject *GO,
86+
SectionKind SK, const TargetMachine &TM) const {
87+
// Place the global in the execute-only text section
88+
if (genExecuteOnly && SK.isText())
89+
SK = SectionKind::getExecuteOnly();
90+
91+
return TargetLoweringObjectFileELF::SelectSectionForGlobal(GO, SK, TM);
92+
}

lib/Target/ARM/ARMTargetObjectFile.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class MCContext;
1818
class TargetMachine;
1919

2020
class ARMElfTargetObjectFile : public TargetLoweringObjectFileELF {
21+
mutable bool genExecuteOnly = false;
2122
protected:
2223
const MCSection *AttributesSection;
2324
public:
@@ -36,6 +37,12 @@ class ARMElfTargetObjectFile : public TargetLoweringObjectFileELF {
3637

3738
/// \brief Describe a TLS variable address within debug info.
3839
const MCExpr *getDebugThreadLocalSymbol(const MCSymbol *Sym) const override;
40+
41+
MCSection *getExplicitSectionGlobal(const GlobalObject *GO, SectionKind Kind,
42+
const TargetMachine &TM) const override;
43+
44+
MCSection *SelectSectionForGlobal(const GlobalObject *GO, SectionKind Kind,
45+
const TargetMachine &TM) const override;
3946
};
4047

4148
} // end namespace llvm

lib/Target/ARM/AsmParser/ARMAsmParser.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5453,6 +5453,9 @@ bool ARMAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
54535453
if (getParser().parseExpression(SubExprVal))
54545454
return true;
54555455
E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
5456+
5457+
// execute-only: we assume that assembly programmers know what they are
5458+
// doing and allow literal pool creation here
54565459
Operands.push_back(ARMOperand::CreateConstantPoolImm(SubExprVal, S, E));
54575460
return false;
54585461
}

0 commit comments

Comments
 (0)