https://github.com/jxz-hw updated https://github.com/llvm/llvm-project/pull/147313
>From 74da236e8ea109543cd423d1128c8dfb30ef4a0a Mon Sep 17 00:00:00 2001 From: jxz-hw <[email protected]> Date: Sun, 7 Jun 2026 20:27:36 +0800 Subject: [PATCH 1/2] [ARM] Support -mlong-calls with -fPIC on ARM ELF targets fix issue #39970 and #142982 - GlobalAddress: use GOT-based addressing via WrapperPIC. DSO-local symbols use a plain PC-relative WrapperPIC; non-DSO-local symbols additionally load the target address from the GOT. - ExternalSymbol: load the symbol address from the GOT via a GOT_PREL constant pool entry followed by a PICLDR. - With -mexecute-only: movw/movt pairs are used instead of constant pools. Note: execute-only may not support PIC; this path is only reached for non-PIC targets. --- llvm/lib/Target/ARM/ARMConstantPoolValue.cpp | 9 +- llvm/lib/Target/ARM/ARMConstantPoolValue.h | 5 +- llvm/lib/Target/ARM/ARMISelLowering.cpp | 50 +++- .../ARM/subtarget-features-long-calls.ll | 261 ++++++++++++++++-- 4 files changed, 287 insertions(+), 38 deletions(-) diff --git a/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp b/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp index 2a3f33fc44b59..1c1d66c83bb73 100644 --- a/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp +++ b/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp @@ -230,10 +230,11 @@ ARMConstantPoolSymbol::ARMConstantPoolSymbol(LLVMContext &C, StringRef s, AddCurrentAddress), S(std::string(s)) {} -ARMConstantPoolSymbol *ARMConstantPoolSymbol::Create(LLVMContext &C, - StringRef s, unsigned ID, - unsigned char PCAdj) { - return new ARMConstantPoolSymbol(C, s, ID, PCAdj, ARMCP::no_modifier, false); +ARMConstantPoolSymbol * +ARMConstantPoolSymbol::Create(LLVMContext &C, StringRef s, unsigned ID, + unsigned char PCAdj, + ARMCP::ARMCPModifier Modifier) { + return new ARMConstantPoolSymbol(C, s, ID, PCAdj, Modifier, false); } int ARMConstantPoolSymbol::getExistingMachineCPValue(MachineConstantPool *CP, diff --git a/llvm/lib/Target/ARM/ARMConstantPoolValue.h b/llvm/lib/Target/ARM/ARMConstantPoolValue.h index e21b2c935c010..2c24b6551c778 100644 --- a/llvm/lib/Target/ARM/ARMConstantPoolValue.h +++ b/llvm/lib/Target/ARM/ARMConstantPoolValue.h @@ -213,8 +213,9 @@ class ARMConstantPoolSymbol : public ARMConstantPoolValue { bool AddCurrentAddress); public: - static ARMConstantPoolSymbol *Create(LLVMContext &C, StringRef s, unsigned ID, - unsigned char PCAdj); + static ARMConstantPoolSymbol * + Create(LLVMContext &C, StringRef s, unsigned ID, unsigned char PCAdj, + ARMCP::ARMCPModifier Modifier = ARMCP::no_modifier); StringRef getSymbol() const { return S; } diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index e08a4f5ebda08..361544ca1396e 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -2438,19 +2438,40 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, auto PtrVt = getPointerTy(DAG.getDataLayout()); if (Subtarget->genLongCalls()) { - assert((!isPositionIndependent() || TT.isOSWindows()) && - "long-calls codegen is not position independent!"); + bool isPIC = isPositionIndependent() && !TT.isOSWindows(); + if (isPIC && Subtarget->genExecuteOnly()) + report_fatal_error(Twine("long-calls with execute-only and " + "position-independent code is not supported"), + /*gen_crash_diag=*/false); + if (Subtarget->isROPI()) + report_fatal_error( + Twine("long-calls with ROPI is not currently supported"), + /*gen_crash_diag=*/false); + // Handle a global address or an external symbol. If it's not one of // those, the target's already in a register, so we don't need to do // anything extra. if (isa<GlobalAddressSDNode>(Callee)) { if (Subtarget->genExecuteOnly()) { + // Execute-only forbids constant pools in .text, so use movw/movt. + // fPIC is not supported with execute-only. if (Subtarget->useMovt()) ++NumMovwMovt; Callee = DAG.getNode(ARMISD::Wrapper, dl, PtrVt, DAG.getTargetGlobalAddress(GVal, dl, PtrVt)); + } else if (isPIC) { + // PIC without execute-only: use GOT-based addressing. + // DSO-local symbols use a plain PC-relative WrapperPIC; + // non-DSO-local symbols additionally load the address from the GOT. + SDValue G = DAG.getTargetGlobalAddress( + GVal, dl, PtrVt, 0, GVal->isDSOLocal() ? 0 : ARMII::MO_GOT); + Callee = DAG.getNode(ARMISD::WrapperPIC, dl, PtrVt, G); + if (!GVal->isDSOLocal()) + Callee = + DAG.getLoad(PtrVt, dl, DAG.getEntryNode(), Callee, + MachinePointerInfo::getGOT(DAG.getMachineFunction())); } else { - // Create a constant pool entry for the callee address + // Neither execute-only nor PIC: load the address from a constant pool. unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = ARMConstantPoolConstant::Create( GVal, ARMPCLabelIndex, ARMCP::CPValue, 0); @@ -2466,12 +2487,31 @@ ARMTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, const char *Sym = S->getSymbol(); if (Subtarget->genExecuteOnly()) { + // Execute-only forbids constant pools in .text, so use movw/movt. + // fPIC is not supported with execute-only. if (Subtarget->useMovt()) ++NumMovwMovt; Callee = DAG.getNode(ARMISD::Wrapper, dl, PtrVt, - DAG.getTargetGlobalAddress(GVal, dl, PtrVt)); + DAG.getTargetExternalSymbol(Sym, PtrVt, 0)); + } else if (isPIC) { + // PIC without execute-only: use GOT-based addressing via a GOT_PREL + // constant pool entry. + unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); + ARMConstantPoolValue *CPV = ARMConstantPoolSymbol::Create( + *DAG.getContext(), Sym, ARMPCLabelIndex, /*PCAdj=*/0, + ARMCP::GOT_PREL); + SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVt, Align(4)); + CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr); + SDValue GOTOffset = DAG.getLoad( + PtrVt, dl, DAG.getEntryNode(), CPAddr, + MachinePointerInfo::getConstantPool(DAG.getMachineFunction())); + SDValue PICLabel = DAG.getConstant(ARMPCLabelIndex, dl, MVT::i32); + Callee = DAG.getNode(ARMISD::PIC_ADD, dl, PtrVt, GOTOffset, PICLabel); + Callee = + DAG.getLoad(PtrVt, dl, DAG.getEntryNode(), Callee, + MachinePointerInfo::getGOT(DAG.getMachineFunction())); } else { - // Create a constant pool entry for the callee address + // Neither execute-only nor PIC: load the address from a constant pool. unsigned ARMPCLabelIndex = AFI->createPICLabelUId(); ARMConstantPoolValue *CPV = ARMConstantPoolSymbol::Create( *DAG.getContext(), Sym, ARMPCLabelIndex, 0); diff --git a/llvm/test/CodeGen/ARM/subtarget-features-long-calls.ll b/llvm/test/CodeGen/ARM/subtarget-features-long-calls.ll index 112a840ba92ee..b8e0884acd67a 100644 --- a/llvm/test/CodeGen/ARM/subtarget-features-long-calls.ll +++ b/llvm/test/CodeGen/ARM/subtarget-features-long-calls.ll @@ -1,44 +1,127 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 ; RUN: llc -mtriple=thumb-- -mcpu=cortex-a8 -relocation-model=static %s -o - | FileCheck -check-prefix=NO-OPTION %s ; RUN: llc -mtriple=thumb-- -mcpu=cortex-a8 -relocation-model=static %s -o - -mattr=+long-calls | FileCheck -check-prefix=LONGCALL %s ; RUN: llc -mtriple=thumb-- -mcpu=cortex-a8 -relocation-model=static %s -o - -mattr=-long-calls | FileCheck -check-prefix=NO-LONGCALL %s ; RUN: llc -mtriple=thumb-- -mcpu=cortex-a8 -relocation-model=static %s -o - -O0 | FileCheck -check-prefix=NO-OPTION %s ; RUN: llc -mtriple=thumb-- -mcpu=cortex-a8 -relocation-model=static %s -o - -O0 -mattr=+long-calls | FileCheck -check-prefix=LONGCALL %s ; RUN: llc -mtriple=thumb-- -mcpu=cortex-a8 -relocation-model=static %s -o - -O0 -mattr=-long-calls | FileCheck -check-prefix=NO-LONGCALL %s - -; NO-OPTION-LABEL: {{_?}}caller0 -; NO-OPTION: ldr [[R0:r[0-9]+]], [[L0:.*]] -; NO-OPTION: blx [[R0]] -; NO-OPTION: [[L0]]: -; NO-OPTION: .long {{_?}}callee0 - -; LONGCALL-LABEL: {{_?}}caller0 -; LONGCALL: ldr [[R0:r[0-9]+]], [[L0:.*]] -; LONGCALL: blx [[R0]] -; LONGCALL: [[L0]]: -; LONGCALL: .long {{_?}}callee0 - -; NO-LONGCALL-LABEL: {{_?}}caller0 -; NO-LONGCALL: bl {{_?}}callee0 +; RUN: llc -mtriple=arm-linux-gnueabi -mcpu=cortex-a8 -relocation-model=static %s -o - -mattr=+long-calls,+execute-only | FileCheck -check-prefix=XO-LONGCALL %s +; RUN: llc -mtriple=arm-linux-gnueabi -mcpu=cortex-a8 -relocation-model=pic %s -o - -mattr=+long-calls | FileCheck -check-prefix=PIC-LONGCALL %s define i32 @caller0() #0 { +; NO-OPTION-LABEL: caller0: +; NO-OPTION: @ %bb.0: @ %entry +; NO-OPTION-NEXT: push {r7, lr} +; NO-OPTION-NEXT: ldr r0, .LCPI0_0 +; NO-OPTION-NEXT: blx r0 +; NO-OPTION-NEXT: movs r0, #0 +; NO-OPTION-NEXT: pop {r7, pc} +; NO-OPTION-NEXT: .p2align 2 +; NO-OPTION-NEXT: @ %bb.1: +; NO-OPTION-NEXT: .LCPI0_0: +; NO-OPTION-NEXT: .long callee0 +; +; LONGCALL-LABEL: caller0: +; LONGCALL: @ %bb.0: @ %entry +; LONGCALL-NEXT: push {r7, lr} +; LONGCALL-NEXT: ldr r0, .LCPI0_0 +; LONGCALL-NEXT: blx r0 +; LONGCALL-NEXT: movs r0, #0 +; LONGCALL-NEXT: pop {r7, pc} +; LONGCALL-NEXT: .p2align 2 +; LONGCALL-NEXT: @ %bb.1: +; LONGCALL-NEXT: .LCPI0_0: +; LONGCALL-NEXT: .long callee0 +; +; NO-LONGCALL-LABEL: caller0: +; NO-LONGCALL: @ %bb.0: @ %entry +; NO-LONGCALL-NEXT: push {r7, lr} +; NO-LONGCALL-NEXT: bl callee0 +; NO-LONGCALL-NEXT: movs r0, #0 +; NO-LONGCALL-NEXT: pop {r7, pc} +; +; XO-LONGCALL-LABEL: caller0: +; XO-LONGCALL: @ %bb.0: @ %entry +; XO-LONGCALL-NEXT: .save {r11, lr} +; XO-LONGCALL-NEXT: push {r11, lr} +; XO-LONGCALL-NEXT: movw r0, :lower16:callee0 +; XO-LONGCALL-NEXT: movt r0, :upper16:callee0 +; XO-LONGCALL-NEXT: blx r0 +; XO-LONGCALL-NEXT: mov r0, #0 +; XO-LONGCALL-NEXT: pop {r11, pc} +; +; PIC-LONGCALL-LABEL: caller0: +; PIC-LONGCALL: @ %bb.0: @ %entry +; PIC-LONGCALL-NEXT: .save {r11, lr} +; PIC-LONGCALL-NEXT: push {r11, lr} +; PIC-LONGCALL-NEXT: ldr r0, .LCPI0_0 +; PIC-LONGCALL-NEXT: .LPC0_0: +; PIC-LONGCALL-NEXT: ldr r0, [pc, r0] +; PIC-LONGCALL-NEXT: blx r0 +; PIC-LONGCALL-NEXT: mov r0, #0 +; PIC-LONGCALL-NEXT: pop {r11, pc} +; PIC-LONGCALL-NEXT: .p2align 2 +; PIC-LONGCALL-NEXT: @ %bb.1: +; PIC-LONGCALL-NEXT: .LCPI0_0: +; PIC-LONGCALL-NEXT: .Ltmp0: +; PIC-LONGCALL-NEXT: .long callee0(GOT_PREL)-(.LPC0_0+8-.Ltmp0) entry: tail call void @callee0() ret i32 0 } -; NO-OPTION-LABEL: {{_?}}caller1 -; NO-OPTION: bl {{_?}}callee0 - -; LONGCALL-LABEL: {{_?}}caller1 -; LONGCALL: ldr [[R0:r[0-9]+]], [[L0:.*]] -; LONGCALL: blx [[R0]] -; LONGCALL: [[L0]]: -; LONGCALL: .long {{_?}}callee0 - -; NO-LONGCALL-LABEL: {{_?}}caller1 -; NO-LONGCALL: bl {{_?}}callee0 - define i32 @caller1() { +; NO-OPTION-LABEL: caller1: +; NO-OPTION: @ %bb.0: @ %entry +; NO-OPTION-NEXT: push {r7, lr} +; NO-OPTION-NEXT: bl callee0 +; NO-OPTION-NEXT: movs r0, #0 +; NO-OPTION-NEXT: pop {r7, pc} +; +; LONGCALL-LABEL: caller1: +; LONGCALL: @ %bb.0: @ %entry +; LONGCALL-NEXT: push {r7, lr} +; LONGCALL-NEXT: ldr r0, .LCPI1_0 +; LONGCALL-NEXT: blx r0 +; LONGCALL-NEXT: movs r0, #0 +; LONGCALL-NEXT: pop {r7, pc} +; LONGCALL-NEXT: .p2align 2 +; LONGCALL-NEXT: @ %bb.1: +; LONGCALL-NEXT: .LCPI1_0: +; LONGCALL-NEXT: .long callee0 +; +; NO-LONGCALL-LABEL: caller1: +; NO-LONGCALL: @ %bb.0: @ %entry +; NO-LONGCALL-NEXT: push {r7, lr} +; NO-LONGCALL-NEXT: bl callee0 +; NO-LONGCALL-NEXT: movs r0, #0 +; NO-LONGCALL-NEXT: pop {r7, pc} +; +; XO-LONGCALL-LABEL: caller1: +; XO-LONGCALL: @ %bb.0: @ %entry +; XO-LONGCALL-NEXT: .save {r11, lr} +; XO-LONGCALL-NEXT: push {r11, lr} +; XO-LONGCALL-NEXT: movw r0, :lower16:callee0 +; XO-LONGCALL-NEXT: movt r0, :upper16:callee0 +; XO-LONGCALL-NEXT: blx r0 +; XO-LONGCALL-NEXT: mov r0, #0 +; XO-LONGCALL-NEXT: pop {r11, pc} +; +; PIC-LONGCALL-LABEL: caller1: +; PIC-LONGCALL: @ %bb.0: @ %entry +; PIC-LONGCALL-NEXT: .save {r11, lr} +; PIC-LONGCALL-NEXT: push {r11, lr} +; PIC-LONGCALL-NEXT: ldr r0, .LCPI1_0 +; PIC-LONGCALL-NEXT: .LPC1_0: +; PIC-LONGCALL-NEXT: ldr r0, [pc, r0] +; PIC-LONGCALL-NEXT: blx r0 +; PIC-LONGCALL-NEXT: mov r0, #0 +; PIC-LONGCALL-NEXT: pop {r11, pc} +; PIC-LONGCALL-NEXT: .p2align 2 +; PIC-LONGCALL-NEXT: @ %bb.1: +; PIC-LONGCALL-NEXT: .LCPI1_0: +; PIC-LONGCALL-NEXT: .Ltmp1: +; PIC-LONGCALL-NEXT: .long callee0(GOT_PREL)-(.LPC1_0+8-.Ltmp1) entry: tail call void @callee0() ret i32 0 @@ -47,3 +130,127 @@ entry: declare void @callee0() attributes #0 = { "target-features"="+long-calls" } + +define dso_local void @global_func() { +; NO-OPTION-LABEL: global_func: +; NO-OPTION: @ %bb.0: @ %entry +; NO-OPTION-NEXT: bx lr +; +; LONGCALL-LABEL: global_func: +; LONGCALL: @ %bb.0: @ %entry +; LONGCALL-NEXT: bx lr +; +; NO-LONGCALL-LABEL: global_func: +; NO-LONGCALL: @ %bb.0: @ %entry +; NO-LONGCALL-NEXT: bx lr +; +; XO-LONGCALL-LABEL: global_func: +; XO-LONGCALL: @ %bb.0: @ %entry +; XO-LONGCALL-NEXT: bx lr +entry: + ret void +} + +define void @test_global() { +; NO-OPTION-LABEL: test_global: +; NO-OPTION: @ %bb.0: @ %entry +; NO-OPTION-NEXT: push {r7, lr} +; NO-OPTION-NEXT: bl global_func +; NO-OPTION-NEXT: pop {r7, pc} +; +; LONGCALL-LABEL: test_global: +; LONGCALL: @ %bb.0: @ %entry +; LONGCALL-NEXT: push {r7, lr} +; LONGCALL-NEXT: ldr r0, .LCPI3_0 +; LONGCALL-NEXT: blx r0 +; LONGCALL-NEXT: pop {r7, pc} +; LONGCALL-NEXT: .p2align 2 +; LONGCALL-NEXT: @ %bb.1: +; LONGCALL-NEXT: .LCPI3_0: +; LONGCALL-NEXT: .long global_func +; +; NO-LONGCALL-LABEL: test_global: +; NO-LONGCALL: @ %bb.0: @ %entry +; NO-LONGCALL-NEXT: push {r7, lr} +; NO-LONGCALL-NEXT: bl global_func +; NO-LONGCALL-NEXT: pop {r7, pc} +; +; XO-LONGCALL-LABEL: test_global: +; XO-LONGCALL: @ %bb.0: @ %entry +; XO-LONGCALL-NEXT: .save {r11, lr} +; XO-LONGCALL-NEXT: push {r11, lr} +; XO-LONGCALL-NEXT: movw r0, :lower16:global_func +; XO-LONGCALL-NEXT: movt r0, :upper16:global_func +; XO-LONGCALL-NEXT: blx r0 +; XO-LONGCALL-NEXT: pop {r11, pc} +; +; PIC-LONGCALL-LABEL: test_global: +; PIC-LONGCALL: @ %bb.0: @ %entry +; PIC-LONGCALL-NEXT: .save {r11, lr} +; PIC-LONGCALL-NEXT: push {r11, lr} +; PIC-LONGCALL-NEXT: ldr r0, .LCPI3_0 +; PIC-LONGCALL-NEXT: .LPC3_0: +; PIC-LONGCALL-NEXT: add r0, pc, r0 +; PIC-LONGCALL-NEXT: blx r0 +; PIC-LONGCALL-NEXT: pop {r11, pc} +; PIC-LONGCALL-NEXT: .p2align 2 +; PIC-LONGCALL-NEXT: @ %bb.1: +; PIC-LONGCALL-NEXT: .LCPI3_0: +; PIC-LONGCALL-NEXT: .long .Lglobal_func$local-(.LPC3_0+8) +entry: + call void @global_func() + ret void +} + +declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) + +define void @test_memset(ptr %dst, i8 %val, i32 %len) { +; NO-OPTION-LABEL: test_memset: +; NO-OPTION: @ %bb.0: @ %entry +; NO-OPTION-NEXT: push {r7, lr} +; NO-OPTION-NEXT: bl memset +; NO-OPTION-NEXT: pop {r7, pc} +; +; LONGCALL-LABEL: test_memset: +; LONGCALL: @ %bb.0: @ %entry +; LONGCALL-NEXT: push {r7, lr} +; LONGCALL-NEXT: ldr r3, .LCPI4_0 +; LONGCALL-NEXT: blx r3 +; LONGCALL-NEXT: pop {r7, pc} +; LONGCALL-NEXT: .p2align 2 +; LONGCALL-NEXT: @ %bb.1: +; LONGCALL-NEXT: .LCPI4_0: +; LONGCALL-NEXT: .long memset +; +; NO-LONGCALL-LABEL: test_memset: +; NO-LONGCALL: @ %bb.0: @ %entry +; NO-LONGCALL-NEXT: push {r7, lr} +; NO-LONGCALL-NEXT: bl memset +; NO-LONGCALL-NEXT: pop {r7, pc} +; +; XO-LONGCALL-LABEL: test_memset: +; XO-LONGCALL: @ %bb.0: @ %entry +; XO-LONGCALL-NEXT: .save {r11, lr} +; XO-LONGCALL-NEXT: push {r11, lr} +; XO-LONGCALL-NEXT: movw r3, :lower16:memset +; XO-LONGCALL-NEXT: movt r3, :upper16:memset +; XO-LONGCALL-NEXT: blx r3 +; XO-LONGCALL-NEXT: pop {r11, pc} +; +; PIC-LONGCALL-LABEL: test_memset: +; PIC-LONGCALL: @ %bb.0: @ %entry +; PIC-LONGCALL-NEXT: .save {r11, lr} +; PIC-LONGCALL-NEXT: push {r11, lr} +; PIC-LONGCALL-NEXT: ldr r3, .LCPI4_0 +; PIC-LONGCALL-NEXT: .LPC4_0: +; PIC-LONGCALL-NEXT: ldr r3, [pc, r3] +; PIC-LONGCALL-NEXT: blx r3 +; PIC-LONGCALL-NEXT: pop {r11, pc} +; PIC-LONGCALL-NEXT: .p2align 2 +; PIC-LONGCALL-NEXT: @ %bb.1: +; PIC-LONGCALL-NEXT: .LCPI4_0: +; PIC-LONGCALL-NEXT: .long memset(GOT_PREL) +entry: + call void @llvm.memset.p0.i32(ptr %dst, i8 %val, i32 %len, i1 false) + ret void +} >From c53cc10eba4dfb636d3e94a64d12a713b5ecd7ec Mon Sep 17 00:00:00 2001 From: jxz-hw <[email protected]> Date: Sat, 13 Jun 2026 01:21:55 +0800 Subject: [PATCH 2/2] [ARM][Clang] Diagnose incompatible -mlong-calls combinations at the driver and function attribute level - -mlong-calls is not compatible with execute-only + position-independent code. Because execute-only uses absolute movw/movt, which conflicts with PIC's GOT-based addressing. - -mlong-calls is not supported for ROPI or RWPI. --- .../clang/Basic/DiagnosticCommonKinds.td | 5 +++ clang/lib/CodeGen/Targets/ARM.cpp | 31 +++++++++++++++++++ clang/lib/Driver/ToolChains/Arch/ARM.cpp | 8 +++++ clang/lib/Driver/ToolChains/Clang.cpp | 9 ++++++ .../CodeGen/arm-long-calls-attr-conflict.c | 12 +++++++ clang/test/Driver/arm-long-calls-conflict.c | 17 ++++++++++ 6 files changed, 82 insertions(+) create mode 100644 clang/test/CodeGen/arm-long-calls-attr-conflict.c create mode 100644 clang/test/Driver/arm-long-calls-conflict.c diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index f2ed2f4698b8d..8a72d39d2a467 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -367,6 +367,11 @@ def err_opt_unsupported_with_suggest : Error< "option '%0' is unsupported; consider using '%1'">; def err_invalid_feature_combination : Error< "invalid feature combination: %0">; +def err_drv_long_calls_unsupported_with_execute_only_pic : Error< + "'-mlong-calls' with '-mexecute-only' is not supported for " + "position-independent code">; +def err_drv_long_calls_unsupported_with_pi : Error< + "'-mlong-calls' is not supported with %select{ROPI|RWPI}0">; def warn_invalid_feature_combination : Warning< "invalid feature combination: %0">, InGroup<DiagGroup<"invalid-feature-combination">>; def warn_target_unrecognized_env : Warning< diff --git a/clang/lib/CodeGen/Targets/ARM.cpp b/clang/lib/CodeGen/Targets/ARM.cpp index c6435dd6f5a8b..74587fa189a58 100644 --- a/clang/lib/CodeGen/Targets/ARM.cpp +++ b/clang/lib/CodeGen/Targets/ARM.cpp @@ -173,6 +173,37 @@ class ARMTargetCodeGenInfo : public TargetCodeGenInfo { setBranchProtectionFnAttributes(BPI, (*Fn)); } + if (FD) { + bool HasLongCalls = false, HasExecOnly = false; + if (Fn->hasFnAttribute("target-features")) { + StringRef Features = + Fn->getFnAttribute("target-features").getValueAsString(); + HasLongCalls = Features.contains("+long-calls"); + HasExecOnly = Features.contains("+execute-only"); + } + + if (HasLongCalls && HasExecOnly) { + auto RelocModel = CGM.getCodeGenOpts().RelocationModel; + if (RelocModel == llvm::Reloc::PIC_) + CGM.getDiags().Report( + D->getLocation(), + diag::err_drv_long_calls_unsupported_with_execute_only_pic); + } + + if (HasLongCalls) { + auto RelocModel = CGM.getCodeGenOpts().RelocationModel; + if (RelocModel == llvm::Reloc::ROPI || + RelocModel == llvm::Reloc::ROPI_RWPI) + CGM.getDiags().Report(D->getLocation(), + diag::err_drv_long_calls_unsupported_with_pi) + << 0; // ROPI + else if (RelocModel == llvm::Reloc::RWPI) + CGM.getDiags().Report(D->getLocation(), + diag::err_drv_long_calls_unsupported_with_pi) + << 1; // RWPI + } + } + if (!FD || !FD->hasAttr<ARMInterruptAttr>()) return; diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 7d9c1f0bd3d40..b5b8bd173926e 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -964,6 +964,14 @@ llvm::ARM::FPUKind arm::getARMTargetFeatures(const Driver &D, } } + // -mlong-calls + -mexecute-only + -fPIC/-fPIE is incompatible. + if (llvm::is_contained(Features, std::string("+long-calls")) && + llvm::is_contained(Features, std::string("+execute-only"))) { + if (Args.getLastArg(options::OPT_fPIC, options::OPT_fpic, options::OPT_fPIE, + options::OPT_fpie)) + D.Diag(diag::err_drv_long_calls_unsupported_with_execute_only_pic); + } + if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access, options::OPT_munaligned_access, options::OPT_mstrict_align, diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index c2ac478d84929..d33f64f038784 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -5742,6 +5742,15 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, !Args.hasArg(options::OPT_fallow_unsupported)) D.Diag(diag::err_drv_ropi_incompatible_with_cxx); + // long-calls is not compatible with ROPI or RWPI. + if ((IsROPI || IsRWPI) && !Args.hasArg(options::OPT_fallow_unsupported)) { + if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, + options::OPT_mno_long_calls)) + if (A->getOption().matches(options::OPT_mlong_calls)) + D.Diag(diag::err_drv_long_calls_unsupported_with_pi) + << (IsROPI ? 0 : 1); // 0=ROPI, 1=RWPI; + } + const char *RMName = RelocationModelName(RelocationModel); if (RMName) { CmdArgs.push_back("-mrelocation-model"); diff --git a/clang/test/CodeGen/arm-long-calls-attr-conflict.c b/clang/test/CodeGen/arm-long-calls-attr-conflict.c new file mode 100644 index 0000000000000..f83ff17103d9b --- /dev/null +++ b/clang/test/CodeGen/arm-long-calls-attr-conflict.c @@ -0,0 +1,12 @@ +// REQUIRES: arm-registered-target +// RUN: not %clang_cc1 -triple armv7a-none-eabi -mrelocation-model pic -emit-obj %s -o /dev/null 2>&1 | FileCheck --check-prefix=ERR-XO-PIC %s +// ERR-XO-PIC: error: '-mlong-calls' with '-mexecute-only' is not supported for position-independent code + +void __attribute__((target("+long-calls,+execute-only"))) +call_xo_pic(void) {} + +// RUN: not %clang_cc1 -triple armv7a-none-eabi -mrelocation-model ropi -emit-obj %s -o /dev/null 2>&1 | FileCheck --check-prefix=ERR-ROPI %s +// ERR-ROPI: error: '-mlong-calls' is not supported with ROPI + +void __attribute__((target("+long-calls"))) +call_ropi(void) {} diff --git a/clang/test/Driver/arm-long-calls-conflict.c b/clang/test/Driver/arm-long-calls-conflict.c new file mode 100644 index 0000000000000..5a63900804d78 --- /dev/null +++ b/clang/test/Driver/arm-long-calls-conflict.c @@ -0,0 +1,17 @@ +// RUN: not %clang --target=armv7a-none-eabi -mlong-calls -mexecute-only -fPIC -### %s 2>&1 | FileCheck --check-prefix=ERR-XO-PIC %s +// ERR-XO-PIC: error: '-mlong-calls' with '-mexecute-only' is not supported for position-independent code + +// RUN: not %clang --target=armv7a-none-eabi -mlong-calls -mexecute-only -fPIE -### %s 2>&1 | FileCheck --check-prefix=ERR-XO-PIE %s +// ERR-XO-PIE: error: '-mlong-calls' with '-mexecute-only' is not supported for position-independent code + +// RUN: %clang --target=armv7a-none-eabi -mlong-calls -mexecute-only -### %s 2>&1 | FileCheck --check-prefix=OK-XO %s +// OK-XO-NOT: error: + +// RUN: not %clang --target=armv7a-none-eabi -mlong-calls -fropi -### %s 2>&1 | FileCheck --check-prefix=ERR-ROPI %s +// ERR-ROPI: error: '-mlong-calls' is not supported with ROPI + +// RUN: not %clang --target=armv7a-none-eabi -mlong-calls -frwpi -### %s 2>&1 | FileCheck --check-prefix=ERR-RWPI %s +// ERR-RWPI: error: '-mlong-calls' is not supported with RWPI + +// RUN: %clang --target=armv7a-none-eabi -mlong-calls -fropi -mno-long-calls -### %s 2>&1 | FileCheck --check-prefix=OK %s +// OK-NOT: error: _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
