[clang] 7e8af2f - [ARM] Support -mexecute-only with -mlong-calls.
Eli Friedman via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 24 11:41:44 PDT 2022
Author: Zhiyao Ma
Date: 2022-10-24T11:41:24-07:00
New Revision: 7e8af2fc0c068de8bb47d8046b8483234fab3b13
URL: https://github.com/llvm/llvm-project/commit/7e8af2fc0c068de8bb47d8046b8483234fab3b13
DIFF: https://github.com/llvm/llvm-project/commit/7e8af2fc0c068de8bb47d8046b8483234fab3b13.diff
LOG: [ARM] Support -mexecute-only with -mlong-calls.
Instead of using constant pools, use movw movt pair.
Differential Revision: https://reviews.llvm.org/D136203
Added:
llvm/test/CodeGen/Thumb2/thumb2-execute-only-long-calls.ll
Modified:
clang/lib/Driver/ToolChains/Arch/ARM.cpp
clang/test/Driver/arm-execute-only.c
llvm/lib/Target/ARM/ARMISelLowering.cpp
Removed:
################################################################################
diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
index a64909d9a6e77..5b3f7c17c307e 100644
--- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp
@@ -776,21 +776,15 @@ void arm::getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
// This only makes sense for the compiler, not for the assembler.
if (!ForAS) {
// Supported only on ARMv6T2 and ARMv7 and above.
- // Cannot be combined with -mno-movt or -mlong-calls
+ // Cannot be combined with -mno-movt.
if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) {
if (A->getOption().matches(options::OPT_mexecute_only)) {
if (getARMSubArchVersionNumber(Triple) < 7 &&
llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2)
D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName();
else if (Arg *B = Args.getLastArg(options::OPT_mno_movt))
- D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args);
- // Long calls create constant pool entries and have not yet been fixed up
- // to play nicely with execute-only. Hence, they cannot be used in
- // execute-only code for now
- else if (Arg *B = Args.getLastArg(options::OPT_mlong_calls, options::OPT_mno_long_calls)) {
- if (B->getOption().matches(options::OPT_mlong_calls))
- D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args);
- }
+ D.Diag(diag::err_opt_not_valid_with_opt)
+ << A->getAsString(Args) << B->getAsString(Args);
Features.push_back("+execute-only");
}
}
diff --git a/clang/test/Driver/arm-execute-only.c b/clang/test/Driver/arm-execute-only.c
index 81b822f1ac068..f69571de10c2a 100644
--- a/clang/test/Driver/arm-execute-only.c
+++ b/clang/test/Driver/arm-execute-only.c
@@ -6,10 +6,6 @@
// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY-NO-MOVT
// CHECK-EXECUTE-ONLY-NO-MOVT: error: option '-mexecute-only' cannot be specified with '-mno-movt'
-// RUN: not %clang -target armv8m.main-eabi -mexecute-only -mlong-calls %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-EXECUTE-ONLY-LONG-CALLS
-// CHECK-EXECUTE-ONLY-LONG-CALLS: error: option '-mexecute-only' cannot be specified with '-mlong-calls'
-
// RUN: %clang -target armv7m-eabi -x assembler -mexecute-only %s -c -### 2>&1 \
// RUN: | FileCheck %s --check-prefix=CHECK-NO-EXECUTE-ONLY-ASM
// CHECK-NO-EXECUTE-ONLY-ASM: warning: argument unused during compilation: '-mexecute-only'
@@ -21,7 +17,3 @@
// RUN: not %clang -target armv8m.main-eabi -mpure-code -mno-movt %s 2>&1 \
// RUN: | FileCheck %s -check-prefix CHECK-PURE-CODE-NO-MOVT
// CHECK-PURE-CODE-NO-MOVT: error: option '-mpure-code' cannot be specified with '-mno-movt'
-
-// RUN: not %clang -target armv8m.main-eabi -mpure-code -mlong-calls %s 2>&1 \
-// RUN: | FileCheck %s -check-prefix CHECK-PURE-CODE-LONG-CALLS
-// CHECK-PURE-CODE-LONG-CALLS: error: option '-mpure-code' cannot be specified with '-mlong-calls'
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index ccfcd89a64403..c84fe4d661974 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -2630,11 +2630,11 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
const TargetMachine &TM = getTargetMachine();
const Module *Mod = MF.getFunction().getParent();
- const GlobalValue *GV = nullptr;
+ const GlobalValue *GVal = nullptr;
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
- GV = G->getGlobal();
+ GVal = G->getGlobal();
bool isStub =
- !TM.shouldAssumeDSOLocal(*Mod, GV) && Subtarget->isTargetMachO();
+ !TM.shouldAssumeDSOLocal(*Mod, GVal) && Subtarget->isTargetMachO();
bool isARMFunc = !Subtarget->isThumb() || (isStub && !Subtarget->isMClass());
bool isLocalARMFunc = false;
@@ -2647,36 +2647,58 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
// those, the target's already in a register, so we don't need to do
// anything extra.
if (isa<GlobalAddressSDNode>(Callee)) {
- // Create a constant pool entry for the callee address
- unsigned ARMPCLabelIndex = AFI->createPICLabelUId();
- ARMConstantPoolValue *CPV =
- ARMConstantPoolConstant::Create(GV, ARMPCLabelIndex, ARMCP::CPValue, 0);
-
- // Get the address of the callee into a register
- SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVt, Align(4));
- CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr);
- Callee = DAG.getLoad(
- PtrVt, dl, DAG.getEntryNode(), CPAddr,
- MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
+ // When generating execute-only code we use movw movt pair.
+ // Currently execute-only is only available for architectures that
+ // support movw movt, so we are safe to assume that.
+ if (Subtarget->genExecuteOnly()) {
+ assert(Subtarget->useMovt() &&
+ "long-calls with execute-only requires movt and movw!");
+ ++NumMovwMovt;
+ Callee = DAG.getNode(ARMISD::Wrapper, dl, PtrVt,
+ DAG.getTargetGlobalAddress(GVal, dl, PtrVt));
+ } else {
+ // Create a constant pool entry for the callee address
+ unsigned ARMPCLabelIndex = AFI->createPICLabelUId();
+ ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create(
+ GVal, ARMPCLabelIndex, ARMCP::CPValue, 0);
+
+ // Get the address of the callee into a register
+ SDValue Addr = DAG.getTargetConstantPool(CPV, PtrVt, Align(4));
+ Addr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Addr);
+ Callee = DAG.getLoad(
+ PtrVt, dl, DAG.getEntryNode(), Addr,
+ MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
+ }
} else if (ExternalSymbolSDNode *S=dyn_cast<ExternalSymbolSDNode>(Callee)) {
const char *Sym = S->getSymbol();
- // Create a constant pool entry for the callee address
- unsigned ARMPCLabelIndex = AFI->createPICLabelUId();
- ARMConstantPoolValue *CPV =
- ARMConstantPoolSymbol::Create(*DAG.getContext(), Sym,
- ARMPCLabelIndex, 0);
- // Get the address of the callee into a register
- SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVt, Align(4));
- CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr);
- Callee = DAG.getLoad(
- PtrVt, dl, DAG.getEntryNode(), CPAddr,
- MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
+ // When generating execute-only code we use movw movt pair.
+ // Currently execute-only is only available for architectures that
+ // support movw movt, so we are safe to assume that.
+ if (Subtarget->genExecuteOnly()) {
+ assert(Subtarget->useMovt() &&
+ "long-calls with execute-only requires movt and movw!");
+ ++NumMovwMovt;
+ Callee = DAG.getNode(ARMISD::Wrapper, dl, PtrVt,
+ DAG.getTargetGlobalAddress(GVal, dl, PtrVt));
+ } else {
+ // Create a constant pool entry for the callee address
+ unsigned ARMPCLabelIndex = AFI->createPICLabelUId();
+ ARMConstantPoolValue *CPV = ARMConstantPoolSymbol::Create(
+ *DAG.getContext(), Sym, ARMPCLabelIndex, 0);
+
+ // Get the address of the callee into a register
+ SDValue Addr = DAG.getTargetConstantPool(CPV, PtrVt, Align(4));
+ Addr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, Addr);
+ Callee = DAG.getLoad(
+ PtrVt, dl, DAG.getEntryNode(), Addr,
+ MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
+ }
}
} else if (isa<GlobalAddressSDNode>(Callee)) {
if (!PreferIndirect) {
isDirect = true;
- bool isDef = GV->isStrongDefinitionForLinker();
+ bool isDef = GVal->isStrongDefinitionForLinker();
// ARM call to a local ARM function is predicable.
isLocalARMFunc = !Subtarget->isThumb() && (isDef || !ARMInterworking);
@@ -2685,7 +2707,7 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
assert(Subtarget->isTargetMachO() && "WrapperPIC use on non-MachO?");
Callee = DAG.getNode(
ARMISD::WrapperPIC, dl, PtrVt,
- DAG.getTargetGlobalAddress(GV, dl, PtrVt, 0, ARMII::MO_NONLAZY));
+ DAG.getTargetGlobalAddress(GVal, dl, PtrVt, 0, ARMII::MO_NONLAZY));
Callee = DAG.getLoad(
PtrVt, dl, DAG.getEntryNode(), Callee,
MachinePointerInfo::getGOT(DAG.getMachineFunction()), MaybeAlign(),
@@ -2695,11 +2717,11 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
assert(Subtarget->isTargetWindows() &&
"Windows is the only supported COFF target");
unsigned TargetFlags = ARMII::MO_NO_FLAG;
- if (GV->hasDLLImportStorageClass())
+ if (GVal->hasDLLImportStorageClass())
TargetFlags = ARMII::MO_DLLIMPORT;
- else if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
+ else if (!TM.shouldAssumeDSOLocal(*GVal->getParent(), GVal))
TargetFlags = ARMII::MO_COFFSTUB;
- Callee = DAG.getTargetGlobalAddress(GV, dl, PtrVt, /*offset=*/0,
+ Callee = DAG.getTargetGlobalAddress(GVal, dl, PtrVt, /*offset=*/0,
TargetFlags);
if (TargetFlags & (ARMII::MO_DLLIMPORT | ARMII::MO_COFFSTUB))
Callee =
@@ -2707,7 +2729,7 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
DAG.getNode(ARMISD::Wrapper, dl, PtrVt, Callee),
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
} else {
- Callee = DAG.getTargetGlobalAddress(GV, dl, PtrVt, 0, 0);
+ Callee = DAG.getTargetGlobalAddress(GVal, dl, PtrVt, 0, 0);
}
}
} else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) {
diff --git a/llvm/test/CodeGen/Thumb2/thumb2-execute-only-long-calls.ll b/llvm/test/CodeGen/Thumb2/thumb2-execute-only-long-calls.ll
new file mode 100644
index 0000000000000..8a70dc2cf273c
--- /dev/null
+++ b/llvm/test/CodeGen/Thumb2/thumb2-execute-only-long-calls.ll
@@ -0,0 +1,35 @@
+; RUN: llc < %s -mtriple=thumbv7em-arm-none-eabi -relocation-model=static | FileCheck %s -check-prefixes=CHECK,STATIC
+; RUN: llc < %s -mtriple=thumbv7em-arm-none-eabi -relocation-model=rwpi | FileCheck %s -check-prefixes=CHECK,RWPI
+
+define void @fn() #0 {
+entry:
+; CHECK-LABEL: fn:
+; CHECK: ldr [[REG:r[0-9]+]], .LCPI0_0
+; CHECK-NEXT: blx [[REG]]
+; CHECK: .LCPI0_0:
+; CHECK-NEXT: .long bar
+ call void @bar()
+ ret void
+}
+
+define void @execute_only_fn() #1 {
+; STATIC-LABEL: execute_only_fn:
+; STATIC: movw [[REG0:r[0-9]+]], :lower16:bar
+; STATIC-NEXT: movt [[REG0]], :upper16:bar
+; STATIC-NEXT: blx [[REG0]]
+; STATIC-NOT: .LCPI0_0:
+
+; RWPI-LABEL: execute_only_fn:
+; RWPI: movw [[REG0:r[0-9]+]], :lower16:bar
+; RWPI-NEXT: movt [[REG0]], :upper16:bar
+; RWPI-NEXT: blx [[REG0]]
+; RWPI-NOT: .LCPI0_0:
+entry:
+ call void @bar()
+ ret void
+}
+
+attributes #0 = { noinline optnone "target-features"="+thumb-mode,+long-calls" }
+attributes #1 = { noinline optnone "target-features"="+execute-only,+thumb-mode,+long-calls" }
+
+declare dso_local void @bar()
More information about the cfe-commits
mailing list