diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -270,6 +270,9 @@ LoongArch Support ^^^^^^^^^^^^^^^^^ +- Patchable function entry (``-fpatchable-function-entry``) is now supported + on LoongArch. + RISC-V Support ^^^^^^^^^^^^^^ - Added ``-mrvv-vector-bits=`` option to give an upper and lower bound on vector diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -792,7 +792,8 @@ def PatchableFunctionEntry : InheritableAttr, TargetSpecificAttr> { + ["aarch64", "aarch64_be", "loongarch32", "loongarch64", "riscv32", + "riscv64", "x86", "x86_64"]>> { let Spellings = [GCC<"patchable_function_entry">]; let Subjects = SubjectList<[Function, ObjCMethod]>; let Args = [UnsignedArgument<"Count">, DefaultIntArgument<"Offset", 0>]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -5328,7 +5328,7 @@ ``M`` defaults to 0 if omitted. This attribute is only supported on -aarch64/aarch64-be/riscv32/riscv64/i386/x86-64 targets. +aarch64/aarch64-be/loongarch32/loongarch64/riscv32/riscv64/i386/x86-64 targets. }]; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6277,7 +6277,8 @@ if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) { StringRef S0 = A->getValue(), S = S0; unsigned Size, Offset = 0; - if (!Triple.isAArch64() && !Triple.isRISCV() && !Triple.isX86()) + if (!Triple.isAArch64() && !Triple.isLoongArch() && !Triple.isRISCV() && + !Triple.isX86()) D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args) << TripleStr; else if (S.consumeInteger(10, Size) || diff --git a/clang/test/Driver/fpatchable-function-entry.c b/clang/test/Driver/fpatchable-function-entry.c --- a/clang/test/Driver/fpatchable-function-entry.c +++ b/clang/test/Driver/fpatchable-function-entry.c @@ -2,6 +2,8 @@ // RUN: %clang -target x86_64 %s -fpatchable-function-entry=1 -c -### 2>&1 | FileCheck %s // RUN: %clang -target aarch64 %s -fpatchable-function-entry=1 -c -### 2>&1 | FileCheck %s // RUN: %clang -target aarch64 %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s +// RUN: %clang -target loongarch32 %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s +// RUN: %clang -target loongarch64 %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s // RUN: %clang -target riscv32 %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s // RUN: %clang -target riscv64 %s -fpatchable-function-entry=1,0 -c -### 2>&1 | FileCheck %s // CHECK: "-fpatchable-function-entry=1" diff --git a/clang/test/Sema/patchable-function-entry-attr.cpp b/clang/test/Sema/patchable-function-entry-attr.cpp --- a/clang/test/Sema/patchable-function-entry-attr.cpp +++ b/clang/test/Sema/patchable-function-entry-attr.cpp @@ -2,6 +2,8 @@ // RUN: %clang_cc1 -triple aarch64_be -fsyntax-only -verify=silence %s // RUN: %clang_cc1 -triple i386 -fsyntax-only -verify=silence %s // RUN: %clang_cc1 -triple x86_64 -fsyntax-only -verify=silence %s +// RUN: %clang_cc1 -triple loongarch32 -fsyntax-only -verify=silence %s +// RUN: %clang_cc1 -triple loongarch64 -fsyntax-only -verify=silence %s // RUN: %clang_cc1 -triple riscv32 -fsyntax-only -verify=silence %s // RUN: %clang_cc1 -triple riscv64 -fsyntax-only -verify=silence %s // RUN: %clang_cc1 -triple ppc64le -fsyntax-only -verify %s diff --git a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.h b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.h --- a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.h +++ b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.h @@ -41,6 +41,8 @@ bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS) override; + void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI); + // tblgen'erated function. bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, const MachineInstr *MI); diff --git a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp --- a/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchAsmPrinter.cpp @@ -35,6 +35,12 @@ if (emitPseudoExpansionLowering(*OutStreamer, MI)) return; + switch (MI->getOpcode()) { + case TargetOpcode::PATCHABLE_FUNCTION_ENTER: + LowerPATCHABLE_FUNCTION_ENTER(*MI); + return; + } + MCInst TmpInst; if (!lowerLoongArchMachineInstrToMCInst(MI, TmpInst, *this)) EmitToStreamer(*OutStreamer, TmpInst); @@ -110,6 +116,22 @@ return false; } +void LoongArchAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER( + const MachineInstr &MI) { + const Function &F = MF->getFunction(); + if (F.hasFnAttribute("patchable-function-entry")) { + unsigned Num; + if (F.getFnAttribute("patchable-function-entry") + .getValueAsString() + .getAsInteger(10, Num)) + return; + emitNops(Num); + return; + } + + // TODO: Emit sled here once we get support for XRay. +} + bool LoongArchAsmPrinter::runOnMachineFunction(MachineFunction &MF) { AsmPrinter::runOnMachineFunction(MF); return true; diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.h @@ -27,6 +27,8 @@ public: explicit LoongArchInstrInfo(LoongArchSubtarget &STI); + MCInst getNop() const override; + void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, MCRegister DstReg, MCRegister SrcReg, bool KillSrc) const override; diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.cpp @@ -17,6 +17,7 @@ #include "MCTargetDesc/LoongArchMCTargetDesc.h" #include "MCTargetDesc/LoongArchMatInt.h" #include "llvm/CodeGen/RegisterScavenging.h" +#include "llvm/MC/MCInstBuilder.h" using namespace llvm; @@ -28,6 +29,13 @@ LoongArch::ADJCALLSTACKUP), STI(STI) {} +MCInst LoongArchInstrInfo::getNop() const { + return MCInstBuilder(LoongArch::ANDI) + .addReg(LoongArch::R0) + .addReg(LoongArch::R0) + .addImm(0); +} + void LoongArchInstrInfo::copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, const DebugLoc &DL, MCRegister DstReg, diff --git a/llvm/test/CodeGen/LoongArch/patchable-function-entry.ll b/llvm/test/CodeGen/LoongArch/patchable-function-entry.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/patchable-function-entry.ll @@ -0,0 +1,63 @@ +;; Test the function attribute "patchable-function-entry". +;; Adapted from the RISCV test case. +; RUN: llc --mtriple=loongarch32 < %s | FileCheck %s --check-prefixes=CHECK,LA32 +; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s --check-prefixes=CHECK,LA64 + +define void @f0() "patchable-function-entry"="0" { +; CHECK-LABEL: f0: +; CHECK-NEXT: .Lfunc_begin0: +; CHECK-NOT: nop +; CHECK: ret +; CHECK-NOT: .section __patchable_function_entries + ret void +} + +define void @f1() "patchable-function-entry"="1" { +; CHECK-LABEL: f1: +; CHECK-NEXT: .Lfunc_begin1: +; CHECK: nop +; CHECK-NEXT: ret +; CHECK: .section __patchable_function_entries,"awo",@progbits,f1{{$}} +; LA32: .p2align 2 +; LA32-NEXT: .word .Lfunc_begin1 +; LA64: .p2align 3 +; LA64-NEXT: .dword .Lfunc_begin1 + ret void +} + +$f5 = comdat any +define void @f5() "patchable-function-entry"="5" comdat { +; CHECK-LABEL: f5: +; CHECK-NEXT: .Lfunc_begin2: +; CHECK-COUNT-5: nop +; CHECK-NEXT: ret +; CHECK: .section __patchable_function_entries,"aGwo",@progbits,f5,comdat,f5{{$}} +; LA32: .p2align 2 +; LA32-NEXT: .word .Lfunc_begin2 +; LA64: .p2align 3 +; LA64-NEXT: .dword .Lfunc_begin2 + ret void +} + +;; -fpatchable-function-entry=3,2 +;; "patchable-function-prefix" emits data before the function entry label. +define void @f3_2() "patchable-function-entry"="1" "patchable-function-prefix"="2" { +; CHECK-LABEL: .type f3_2,@function +; CHECK-NEXT: .Ltmp0: # @f3_2 +; CHECK-COUNT-2: nop +; CHECK-NEXT: f3_2: +; CHECK: # %bb.0: +; CHECK-NEXT: nop +; LA32-NEXT: addi.w $sp, $sp, -16 +; LA64-NEXT: addi.d $sp, $sp, -16 +;; .size does not include the prefix. +; CHECK: .Lfunc_end3: +; CHECK-NEXT: .size f3_2, .Lfunc_end3-f3_2 +; CHECK: .section __patchable_function_entries,"awo",@progbits,f3_2{{$}} +; LA32: .p2align 2 +; LA32-NEXT: .word .Ltmp0 +; LA64: .p2align 3 +; LA64-NEXT: .dword .Ltmp0 + %frame = alloca i8, i32 16 + ret void +}