forked from OSchip/llvm-project
[RISCV] Support clang -fpatchable-function-entry && GNU function attribute 'patchable_function_entry'
Similar to D72215 (AArch64) and D72220 (x86). ``` % clang -target riscv32 -march=rv64g -c -fpatchable-function-entry=2 a.c && llvm-objdump -dr a.o ... 0000000000000000 <main>: 0: 13 00 00 00 nop 4: 13 00 00 00 nop % clang -target riscv32 -march=rv64gc -c -fpatchable-function-entry=2 a.c && llvm-objdump -dr a.o ... 00000002 <main>: 2: 01 00 nop 4: 01 00 nop ``` Recently the mainline kernel started to use -fpatchable-function-entry=8 for riscv (https://git.kernel.org/linus/afc76b8b80112189b6f11e67e19cf58301944814). Differential Revision: https://reviews.llvm.org/D98610
This commit is contained in:
parent
6513995be3
commit
6ab8927931
|
@ -730,7 +730,8 @@ def XRayLogArgs : InheritableAttr {
|
|||
|
||||
def PatchableFunctionEntry
|
||||
: InheritableAttr,
|
||||
TargetSpecificAttr<TargetArch<["aarch64", "aarch64_be", "x86", "x86_64"]>> {
|
||||
TargetSpecificAttr<TargetArch<
|
||||
["aarch64", "aarch64_be", "riscv32", "riscv64", "x86", "x86_64"]>> {
|
||||
let Spellings = [GCC<"patchable_function_entry">];
|
||||
let Subjects = SubjectList<[Function, ObjCMethod]>;
|
||||
let Args = [UnsignedArgument<"Count">, DefaultIntArgument<"Offset", 0>];
|
||||
|
|
|
@ -4810,6 +4810,9 @@ def PatchableFunctionEntryDocs : Documentation {
|
|||
before the function entry and N-M NOPs after the function entry. This attribute
|
||||
takes precedence over the command line option ``-fpatchable-function-entry=N,M``.
|
||||
``M`` defaults to 0 if omitted.
|
||||
|
||||
This attribute is only supported on
|
||||
aarch64/aarch64-be/riscv32/riscv64/i386/x86-64 targets.
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
@ -5614,8 +5614,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
|||
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.getArch() != llvm::Triple::x86 &&
|
||||
Triple.getArch() != llvm::Triple::x86_64)
|
||||
if (!Triple.isAArch64() && !Triple.isRISCV() && !Triple.isX86())
|
||||
D.Diag(diag::err_drv_unsupported_opt_for_target)
|
||||
<< A->getAsString(Args) << TripleStr;
|
||||
else if (S.consumeInteger(10, Size) ||
|
||||
|
|
|
@ -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 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"
|
||||
|
||||
// RUN: %clang -target aarch64 -fsyntax-only %s -fpatchable-function-entry=1,1 -c -### 2>&1 | FileCheck --check-prefix=11 %s
|
||||
|
|
|
@ -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 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
|
||||
|
||||
// silence-no-diagnostics
|
||||
|
|
|
@ -30,8 +30,8 @@ class MachineInstr;
|
|||
class MachineOperand;
|
||||
class PassRegistry;
|
||||
|
||||
void LowerRISCVMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
|
||||
const AsmPrinter &AP);
|
||||
bool lowerRISCVMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
|
||||
AsmPrinter &AP);
|
||||
bool LowerRISCVMachineOperandToMCOperand(const MachineOperand &MO,
|
||||
MCOperand &MCOp, const AsmPrinter &AP);
|
||||
|
||||
|
|
|
@ -93,8 +93,8 @@ void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {
|
|||
return;
|
||||
|
||||
MCInst TmpInst;
|
||||
LowerRISCVMachineInstrToMCInst(MI, TmpInst, *this);
|
||||
EmitToStreamer(*OutStreamer, TmpInst);
|
||||
if (!lowerRISCVMachineInstrToMCInst(MI, TmpInst, *this))
|
||||
EmitToStreamer(*OutStreamer, TmpInst);
|
||||
}
|
||||
|
||||
bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/RegisterScavenging.h"
|
||||
#include "llvm/MC/MCInstBuilder.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
|
||||
|
@ -49,6 +50,15 @@ RISCVInstrInfo::RISCVInstrInfo(RISCVSubtarget &STI)
|
|||
: RISCVGenInstrInfo(RISCV::ADJCALLSTACKDOWN, RISCV::ADJCALLSTACKUP),
|
||||
STI(STI) {}
|
||||
|
||||
MCInst RISCVInstrInfo::getNop() const {
|
||||
if (STI.getFeatureBits()[RISCV::FeatureStdExtC])
|
||||
return MCInstBuilder(RISCV::C_NOP);
|
||||
return MCInstBuilder(RISCV::ADDI)
|
||||
.addReg(RISCV::X0)
|
||||
.addReg(RISCV::X0)
|
||||
.addImm(0);
|
||||
}
|
||||
|
||||
unsigned RISCVInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
|
||||
int &FrameIndex) const {
|
||||
switch (MI.getOpcode()) {
|
||||
|
|
|
@ -29,6 +29,8 @@ class RISCVInstrInfo : public RISCVGenInstrInfo {
|
|||
public:
|
||||
explicit RISCVInstrInfo(RISCVSubtarget &STI);
|
||||
|
||||
MCInst getNop() const override;
|
||||
|
||||
unsigned isLoadFromStackSlot(const MachineInstr &MI,
|
||||
int &FrameIndex) const override;
|
||||
unsigned isStoreToStackSlot(const MachineInstr &MI,
|
||||
|
|
|
@ -204,10 +204,10 @@ static bool lowerRISCVVMachineInstrToMCInst(const MachineInstr *MI,
|
|||
return true;
|
||||
}
|
||||
|
||||
void llvm::LowerRISCVMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
|
||||
const AsmPrinter &AP) {
|
||||
bool llvm::lowerRISCVMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
|
||||
AsmPrinter &AP) {
|
||||
if (lowerRISCVVMachineInstrToMCInst(MI, OutMI))
|
||||
return;
|
||||
return false;
|
||||
|
||||
OutMI.setOpcode(MI->getOpcode());
|
||||
|
||||
|
@ -217,19 +217,32 @@ void llvm::LowerRISCVMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI,
|
|||
OutMI.addOperand(MCOp);
|
||||
}
|
||||
|
||||
if (OutMI.getOpcode() == RISCV::PseudoReadVLENB) {
|
||||
switch (OutMI.getOpcode()) {
|
||||
case TargetOpcode::PATCHABLE_FUNCTION_ENTER: {
|
||||
const Function &F = MI->getParent()->getParent()->getFunction();
|
||||
if (F.hasFnAttribute("patchable-function-entry")) {
|
||||
unsigned Num;
|
||||
if (F.getFnAttribute("patchable-function-entry")
|
||||
.getValueAsString()
|
||||
.getAsInteger(10, Num))
|
||||
return false;
|
||||
AP.emitNops(Num);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RISCV::PseudoReadVLENB:
|
||||
OutMI.setOpcode(RISCV::CSRRS);
|
||||
OutMI.addOperand(MCOperand::createImm(
|
||||
RISCVSysReg::lookupSysRegByName("VLENB")->Encoding));
|
||||
OutMI.addOperand(MCOperand::createReg(RISCV::X0));
|
||||
return;
|
||||
}
|
||||
|
||||
if (OutMI.getOpcode() == RISCV::PseudoReadVL) {
|
||||
break;
|
||||
case RISCV::PseudoReadVL:
|
||||
OutMI.setOpcode(RISCV::CSRRS);
|
||||
OutMI.addOperand(MCOperand::createImm(
|
||||
RISCVSysReg::lookupSysRegByName("VL")->Encoding));
|
||||
OutMI.addOperand(
|
||||
MCOperand::createImm(RISCVSysReg::lookupSysRegByName("VL")->Encoding));
|
||||
OutMI.addOperand(MCOperand::createReg(RISCV::X0));
|
||||
return;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
;; Test the function attribute "patchable-function-entry".
|
||||
; RUN: llc -mtriple=riscv32 --riscv-no-aliases < %s | FileCheck %s --check-prefixes=CHECK,RV32,NORVC
|
||||
; RUN: llc -mtriple=riscv64 --riscv-no-aliases < %s | FileCheck %s --check-prefixes=CHECK,RV64,NORVC
|
||||
; RUN: llc -mtriple=riscv32 -mattr=+c --riscv-no-aliases < %s | FileCheck %s --check-prefixes=CHECK,RV32,RVC
|
||||
; RUN: llc -mtriple=riscv64 -mattr=+c --riscv-no-aliases < %s | FileCheck %s --check-prefixes=CHECK,RV64,RVC
|
||||
|
||||
define void @f0() "patchable-function-entry"="0" {
|
||||
; CHECK-LABEL: f0:
|
||||
; CHECK-NEXT: .Lfunc_begin0:
|
||||
; CHECK-NOT: {{addi|c.nop}}
|
||||
; NORVC: jalr zero, 0(ra)
|
||||
; RVC: c.jr ra
|
||||
; CHECK-NOT: .section __patchable_function_entries
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f1() "patchable-function-entry"="1" {
|
||||
; CHECK-LABEL: f1:
|
||||
; CHECK-NEXT: .Lfunc_begin1:
|
||||
; NORVC: addi zero, zero, 0
|
||||
; NORVC-NEXT: jalr zero, 0(ra)
|
||||
; RVC: c.nop
|
||||
; RVC-NEXT: c.jr ra
|
||||
; CHECK: .section __patchable_function_entries,"awo",@progbits,f1{{$}}
|
||||
; 32: .p2align 2
|
||||
; 32-NEXT: .word .Lfunc_begin1
|
||||
; 64: .p2align 3
|
||||
; 64-NEXT: .quad .Lfunc_begin1
|
||||
ret void
|
||||
}
|
||||
|
||||
$f5 = comdat any
|
||||
define void @f5() "patchable-function-entry"="5" comdat {
|
||||
; CHECK-LABEL: f5:
|
||||
; CHECK-NEXT: .Lfunc_begin2:
|
||||
; NORVC-COUNT-5: addi zero, zero, 0
|
||||
; NORVC-NEXT: jalr zero, 0(ra)
|
||||
; RVC-COUNT-5: c.nop
|
||||
; RVC-NEXT: c.jr ra
|
||||
; CHECK: .section __patchable_function_entries,"aGwo",@progbits,f5,comdat,f5{{$}}
|
||||
; RV32: .p2align 2
|
||||
; RV32-NEXT: .word .Lfunc_begin2
|
||||
; RV64: .p2align 3
|
||||
; RV64-NEXT: .quad .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
|
||||
; NORVC-COUNT-2: addi zero, zero, 0
|
||||
; RVC-COUNT-2: c.nop
|
||||
; CHECK-NEXT: f3_2:
|
||||
; CHECK: # %bb.0:
|
||||
; NORVC-NEXT: addi zero, zero, 0
|
||||
; NORVC-NEXT: addi sp, sp, -16
|
||||
; RVC-NEXT: c.nop
|
||||
; RVC-NEXT: c.addi 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{{$}}
|
||||
; RV32: .p2align 2
|
||||
; RV32-NEXT: .word .Ltmp0
|
||||
; RV64: .p2align 3
|
||||
; RV64-NEXT: .quad .Ltmp0
|
||||
%frame = alloca i8, i32 16
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue