Skip to content

Commit e135e62

Browse files
committed
[RISCV][Zicfilp] Codegen LPAD insns by looking at module flags
Expected Behavior: Stop codegening LPAD insns by testing if the target has the Zicfilp extension and instead, codegen LPAD insns if the LLVM module has all of these flags: + `cf-protection-branch`: Needs to be a non-zero integer (which means `true`) + `cf-branch-label-scheme`: Needs to be `unlabeled` Context: In clang, Zicfilp-based control flow integrity (the `unlabeled` scheme) can now be enabled by giving the `-fcf-protection=branch -mcf-branch-label-scheme=unlabeled` options. With these options, the clang frontend adds the above-mentioned flags to LLVM modules. Here we want to align LPAD insn codegen to be enabled by the semantics of those LLVM module flags, instead of relying on the inaccurate indicator of whether the Zicfilp extension is available, so the toolchain's behavior is more streamlined and expected. Also, since LPAD insns can be executed regardless of whether Zicfilp is available in target or not (due to LPAD insn being encoded as a standard hint insn), clang accepts the above-mentioned CLI options even if Zicfilp is not enabled and expects backend to still generate LPAD insns. This patch enables LPAD insn generation in such cases.
1 parent 2317347 commit e135e62

36 files changed

+3304
-2202
lines changed

clang/lib/Driver/ToolChains/Arch/RISCV.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,35 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
169169
Features.push_back("+unaligned-vector-mem");
170170
}
171171

172+
if (const Arg *A = Args.getLastArg(options::OPT_fcf_protection_EQ)) {
173+
const StringRef CFProtection{A->getValue()};
174+
const bool CFProtectionBranch =
175+
CFProtection == "full" || CFProtection == "branch";
176+
if (CFProtectionBranch) {
177+
bool FuncSig;
178+
if (const Arg *SA =
179+
Args.getLastArg(options::OPT_mcf_branch_label_scheme_EQ)) {
180+
const StringRef Scheme{SA->getValue()};
181+
if (Scheme == "unlabeled") {
182+
FuncSig = false;
183+
} else {
184+
assert(Scheme == "func-sig" &&
185+
"-mcf-branch-label-scheme should be either `unlabeled` or "
186+
"`func-sig`");
187+
FuncSig = true;
188+
}
189+
} else {
190+
// `func-sig` is assumed if `-mcf-branch-label-scheme` is not given.
191+
FuncSig = true;
192+
}
193+
194+
if (FuncSig)
195+
Features.push_back("+zicfilp-func-sig");
196+
else
197+
Features.push_back("+zicfilp-unlabeled");
198+
}
199+
}
200+
172201
// Now add any that the user explicitly requested on the command line,
173202
// which may override the defaults.
174203
handleTargetFeaturesGroup(D, Triple, Args, Features,

clang/test/Driver/riscv-features.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,3 +90,22 @@
9090

9191
// RVE: "-target-feature" "+e"
9292
// RVE-SAME: "-target-feature" "-i"
93+
94+
// RUN: %clang --target=riscv32 -fcf-protection=full -### %s -fsyntax-only 2>&1 | FileCheck %s -check-prefixes=ZICFILP-FUNC-SIG
95+
// RUN: %clang --target=riscv32 -fcf-protection=full -mcf-branch-label-scheme=func-sig -### %s -fsyntax-only 2>&1 | FileCheck %s -check-prefixes=ZICFILP-FUNC-SIG
96+
// RUN: %clang --target=riscv32 -fcf-protection=full -mcf-branch-label-scheme=unlabeled -### %s -fsyntax-only 2>&1 | FileCheck %s -check-prefixes=ZICFILP-UNLABELED
97+
// RUN: %clang --target=riscv32 -fcf-protection=branch -### %s -fsyntax-only 2>&1 | FileCheck %s -check-prefixes=ZICFILP-FUNC-SIG
98+
// RUN: %clang --target=riscv32 -fcf-protection=branch -mcf-branch-label-scheme=func-sig -### %s -fsyntax-only 2>&1 | FileCheck %s -check-prefixes=ZICFILP-FUNC-SIG
99+
// RUN: %clang --target=riscv32 -fcf-protection=branch -mcf-branch-label-scheme=unlabeled -### %s -fsyntax-only 2>&1 | FileCheck %s -check-prefixes=ZICFILP-UNLABELED
100+
// RUN: %clang --target=riscv64 -fcf-protection=full -### %s -fsyntax-only 2>&1 | FileCheck %s -check-prefixes=ZICFILP-FUNC-SIG
101+
// RUN: %clang --target=riscv64 -fcf-protection=full -mcf-branch-label-scheme=func-sig -### %s -fsyntax-only 2>&1 | FileCheck %s -check-prefixes=ZICFILP-FUNC-SIG
102+
// RUN: %clang --target=riscv64 -fcf-protection=full -mcf-branch-label-scheme=unlabeled -### %s -fsyntax-only 2>&1 | FileCheck %s -check-prefixes=ZICFILP-UNLABELED
103+
// RUN: %clang --target=riscv64 -fcf-protection=branch -### %s -fsyntax-only 2>&1 | FileCheck %s -check-prefixes=ZICFILP-FUNC-SIG
104+
// RUN: %clang --target=riscv64 -fcf-protection=branch -mcf-branch-label-scheme=func-sig -### %s -fsyntax-only 2>&1 | FileCheck %s -check-prefixes=ZICFILP-FUNC-SIG
105+
// RUN: %clang --target=riscv64 -fcf-protection=branch -mcf-branch-label-scheme=unlabeled -### %s -fsyntax-only 2>&1 | FileCheck %s -check-prefixes=ZICFILP-UNLABELED
106+
// ZICFILP-FUNC-SIG-NOT: "-target-feature" "-zicfilp-unlabeled"
107+
// ZICFILP-FUNC-SIG: "-target-feature" "+zicfilp-func-sig"
108+
// ZICFILP-FUNC-SIG-NOT: "-target-feature" "-zicfilp-unlabeled"
109+
// ZICFILP-UNLABELED-NOT: "-target-feature" "-zicfilp-func-sig"
110+
// ZICFILP-UNLABELED: "-target-feature" "+zicfilp-unlabeled"
111+
// ZICFILP-UNLABELED-NOT: "-target-feature" "-zicfilp-func-sig"

llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ void validate(const Triple &TT, const FeatureBitset &FeatureBits) {
134134
if (FeatureBits[RISCV::Feature32Bit] &&
135135
FeatureBits[RISCV::Feature64Bit])
136136
reportFatalUsageError("RV32 and RV64 can't be combined");
137+
if (FeatureBits[RISCV::FeatureZicfilpFuncSig] &&
138+
FeatureBits[RISCV::FeatureZicfilpUnlabeled])
139+
reportFatalUsageError(
140+
"+zicfilp-func-sig and +zicfilp-unlabeled can't be combined");
137141
}
138142

139143
llvm::Expected<std::unique_ptr<RISCVISAInfo>>

llvm/lib/Target/RISCV/RISCVCallingConv.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,7 @@ bool llvm::CC_RISCV(unsigned ValNo, MVT ValVT, MVT LocVT,
337337
// Static chain parameter must not be passed in normal argument registers,
338338
// so we assign t2/t3 for it as done in GCC's
339339
// __builtin_call_with_static_chain
340-
bool HasCFBranch =
341-
Subtarget.hasStdExtZicfilp() &&
342-
MF.getFunction().getParent()->getModuleFlag("cf-protection-branch");
340+
bool HasCFBranch = Subtarget.hasZicfilpCFI();
343341

344342
// Normal: t2, Branch control flow protection: t3
345343
const auto StaticChainReg = HasCFBranch ? RISCV::X28 : RISCV::X7;

llvm/lib/Target/RISCV/RISCVFeatures.td

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,6 @@ def FeatureStdExtZicfilp
176176
def HasStdExtZicfilp : Predicate<"Subtarget->hasStdExtZicfilp()">,
177177
AssemblerPredicate<(all_of FeatureStdExtZicfilp),
178178
"'Zicfilp' (Landing pad)">;
179-
def NoStdExtZicfilp : Predicate<"!Subtarget->hasStdExtZicfilp()">,
180-
AssemblerPredicate<(all_of (not FeatureStdExtZicfilp))>;
181179

182180
def FeatureStdExtZicfiss
183181
: RISCVExperimentalExtension<1, 0, "Shadow stack",
@@ -1976,3 +1974,14 @@ def TuneSiFive7 : SubtargetFeature<"sifive7", "RISCVProcFamily", "SiFive7",
19761974
def TuneVentanaVeyron : SubtargetFeature<"ventana-veyron", "RISCVProcFamily", "VentanaVeyron",
19771975
"Ventana Veyron-Series processors">;
19781976

1977+
// Zicfilp-based CFI
1978+
def FeatureZicfilpUnlabeled
1979+
: SubtargetFeature<
1980+
"zicfilp-unlabeled", "RISCVZicfilpCFIScheme", "ZicfilpUnlabeled",
1981+
"Enforce forward-edge control-flow integrity with ZICFILP-unlabeled">;
1982+
def FeatureZicfilpFuncSig
1983+
: SubtargetFeature<
1984+
"zicfilp-func-sig", "RISCVZicfilpCFIScheme", "ZicfilpFuncSig",
1985+
"Enforce forward-edge control-flow integrity with ZICFILP-func-sig">;
1986+
def HasZicfilpCFI : Predicate<"Subtarget->hasZicfilpCFI()">;
1987+
def NoZicfilpCFI : Predicate<"!Subtarget->hasZicfilpCFI()">;

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8969,10 +8969,7 @@ SDValue RISCVTargetLowering::lowerINIT_TRAMPOLINE(SDValue Op,
89698969
// 28: <FunctionAddressOffset>
89708970
// 36:
89718971

8972-
const bool HasCFBranch =
8973-
Subtarget.hasStdExtZicfilp() &&
8974-
DAG.getMachineFunction().getFunction().getParent()->getModuleFlag(
8975-
"cf-protection-branch");
8972+
const bool HasCFBranch = Subtarget.hasZicfilpCFI();
89768973
const unsigned StaticChainIdx = HasCFBranch ? 5 : 4;
89778974
const unsigned StaticChainOffset = StaticChainIdx * 4;
89788975
const unsigned FunctionAddressOffset = StaticChainOffset + 8;
@@ -24082,11 +24079,10 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI,
2408224079
// Use software guarded branch for large code model non-indirect calls
2408324080
// Tail call to external symbol will have a null CLI.CB and we need another
2408424081
// way to determine the callsite type
24085-
bool NeedSWGuarded = false;
24086-
if (getTargetMachine().getCodeModel() == CodeModel::Large &&
24087-
Subtarget.hasStdExtZicfilp() &&
24088-
((CLI.CB && !CLI.CB->isIndirectCall()) || CalleeIsLargeExternalSymbol))
24089-
NeedSWGuarded = true;
24082+
const bool NeedSWGuarded =
24083+
getTargetMachine().getCodeModel() == CodeModel::Large &&
24084+
Subtarget.hasZicfilpCFI() &&
24085+
((CLI.CB && !CLI.CB->isIndirectCall()) || CalleeIsLargeExternalSymbol);
2409024086

2409124087
if (IsTailCall) {
2409224088
MF.getFrameInfo().setHasTailCall();
@@ -25722,8 +25718,8 @@ SDValue RISCVTargetLowering::expandIndirectJTBranch(const SDLoc &dl,
2572225718
SDValue Value, SDValue Addr,
2572325719
int JTI,
2572425720
SelectionDAG &DAG) const {
25725-
if (Subtarget.hasStdExtZicfilp()) {
25726-
// When Zicfilp enabled, we need to use software guarded branch for jump
25721+
if (Subtarget.hasZicfilpCFI()) {
25722+
// When Zicfilp CFI is used, we need to use software guarded branch for jump
2572725723
// table branch.
2572825724
SDValue Chain = Value;
2572925725
// Jump table debug info is only needed if CodeView is enabled.

llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "llvm/CodeGen/MachineFunctionPass.h"
2121
#include "llvm/CodeGen/MachineInstrBuilder.h"
2222
#include "llvm/CodeGen/MachineModuleInfo.h"
23+
#include "llvm/Support/Error.h"
2324

2425
#define DEBUG_TYPE "riscv-indirect-branch-tracking"
2526
#define PASS_NAME "RISC-V Indirect Branch Tracking"
@@ -76,10 +77,15 @@ static bool isCallReturnTwice(const MachineOperand &MOp) {
7677

7778
bool RISCVIndirectBranchTracking::runOnMachineFunction(MachineFunction &MF) {
7879
const auto &Subtarget = MF.getSubtarget<RISCVSubtarget>();
79-
const RISCVInstrInfo *TII = Subtarget.getInstrInfo();
80-
if (!Subtarget.hasStdExtZicfilp())
80+
if (!Subtarget.hasZicfilpCFI())
8181
return false;
8282

83+
const RISCVInstrInfo *TII = Subtarget.getInstrInfo();
84+
85+
if (Subtarget.getZicfilpCFIScheme() != RISCVSubtarget::ZicfilpUnlabeled)
86+
reportFatalUsageError(
87+
"only cf-branch-label-scheme=unlabeled is supported for now");
88+
8389
uint32_t FixedLabel = 0;
8490
if (PreferredLandingPadLabel.getNumOccurrences() > 0) {
8591
if (!isUInt<20>(PreferredLandingPadLabel))

llvm/lib/Target/RISCV/RISCVInstrInfo.td

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1758,12 +1758,12 @@ let isBarrier = 1, isBranch = 1, isTerminator = 1 in
17581758
def PseudoBR : Pseudo<(outs), (ins simm21_lsb0_jal:$imm20), [(br bb:$imm20)]>,
17591759
PseudoInstExpansion<(JAL X0, simm21_lsb0_jal:$imm20)>;
17601760

1761-
let Predicates = [NoStdExtZicfilp],
1761+
let Predicates = [NoZicfilpCFI],
17621762
isBarrier = 1, isBranch = 1, isIndirectBranch = 1, isTerminator = 1 in
17631763
def PseudoBRIND : Pseudo<(outs), (ins GPRJALR:$rs1, simm12_lo:$imm12), []>,
17641764
PseudoInstExpansion<(JALR X0, GPR:$rs1, simm12_lo:$imm12)>;
17651765

1766-
let Predicates = [HasStdExtZicfilp],
1766+
let Predicates = [HasZicfilpCFI],
17671767
isBarrier = 1, isBranch = 1, isIndirectBranch = 1, isTerminator = 1 in {
17681768
def PseudoBRINDNonX7 : Pseudo<(outs), (ins GPRJALRNonX7:$rs1, simm12_lo:$imm12), []>,
17691769
PseudoInstExpansion<(JALR X0, GPR:$rs1, simm12_lo:$imm12)>;
@@ -1773,7 +1773,7 @@ def PseudoBRINDX7 : Pseudo<(outs), (ins GPRX7:$rs1, simm12_lo:$imm12), []>,
17731773

17741774
// For Zicfilp, need to avoid using X7/T2 for indirect branches which need
17751775
// landing pad.
1776-
let Predicates = [HasStdExtZicfilp] in {
1776+
let Predicates = [HasZicfilpCFI] in {
17771777
def : Pat<(brind GPRJALRNonX7:$rs1), (PseudoBRINDNonX7 GPRJALRNonX7:$rs1, 0)>;
17781778
def : Pat<(brind (add GPRJALRNonX7:$rs1, simm12_lo:$imm12)),
17791779
(PseudoBRINDNonX7 GPRJALRNonX7:$rs1, simm12_lo:$imm12)>;
@@ -1783,7 +1783,7 @@ def : Pat<(riscv_sw_guarded_brind (add GPRX7:$rs1, simm12_lo:$imm12)),
17831783
(PseudoBRINDX7 GPRX7:$rs1, simm12_lo:$imm12)>;
17841784
}
17851785

1786-
let Predicates = [NoStdExtZicfilp] in {
1786+
let Predicates = [NoZicfilpCFI] in {
17871787
def : Pat<(brind GPRJALR:$rs1), (PseudoBRIND GPRJALR:$rs1, 0)>;
17881788
def : Pat<(brind (add GPRJALR:$rs1, simm12_lo:$imm12)),
17891789
(PseudoBRIND GPRJALR:$rs1, simm12_lo:$imm12)>;
@@ -1820,11 +1820,11 @@ let Predicates = [HasStdExtSmrnmi] in
18201820
def : Pat<(riscv_mnret_glue), (MNRET)>;
18211821

18221822
let isCall = 1, Defs = [X1] in {
1823-
let Predicates = [NoStdExtZicfilp] in
1823+
let Predicates = [NoZicfilpCFI] in
18241824
def PseudoCALLIndirect : Pseudo<(outs), (ins GPRJALR:$rs1),
18251825
[(riscv_call GPRJALR:$rs1)]>,
18261826
PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>;
1827-
let Predicates = [HasStdExtZicfilp] in {
1827+
let Predicates = [HasZicfilpCFI] in {
18281828
def PseudoCALLIndirectNonX7 : Pseudo<(outs), (ins GPRJALRNonX7:$rs1),
18291829
[(riscv_call GPRJALRNonX7:$rs1)]>,
18301830
PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>;
@@ -1849,11 +1849,11 @@ def PseudoTAIL : Pseudo<(outs), (ins call_symbol:$dst), [],
18491849
Sched<[WriteIALU, WriteJalr, ReadJalr]>;
18501850

18511851
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [X2] in {
1852-
let Predicates = [NoStdExtZicfilp] in
1852+
let Predicates = [NoZicfilpCFI] in
18531853
def PseudoTAILIndirect : Pseudo<(outs), (ins GPRTC:$rs1),
18541854
[(riscv_tail GPRTC:$rs1)]>,
18551855
PseudoInstExpansion<(JALR X0, GPR:$rs1, 0)>;
1856-
let Predicates = [HasStdExtZicfilp] in {
1856+
let Predicates = [HasZicfilpCFI] in {
18571857
def PseudoTAILIndirectNonX7 : Pseudo<(outs), (ins GPRTCNonX7:$rs1),
18581858
[(riscv_tail GPRTCNonX7:$rs1)]>,
18591859
PseudoInstExpansion<(JALR X0, GPR:$rs1, 0)>;

llvm/lib/Target/RISCV/RISCVLandingPadSetup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ bool RISCVLandingPadSetup::runOnMachineFunction(MachineFunction &MF) {
4848
const auto &STI = MF.getSubtarget<RISCVSubtarget>();
4949
const RISCVInstrInfo &TII = *STI.getInstrInfo();
5050

51-
if (!STI.hasStdExtZicfilp())
51+
if (!STI.hasZicfilpCFI())
5252
return false;
5353

5454
uint32_t Label = 0;

llvm/lib/Target/RISCV/RISCVSubtarget.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,19 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
9090
Quadratic,
9191
NLog2N,
9292
};
93+
enum RISCVZicfilpCFISchemeEnum : uint8_t {
94+
ZicfilpDisabled,
95+
ZicfilpUnlabeled,
96+
ZicfilpFuncSig,
97+
};
9398
// clang-format on
99+
94100
private:
95101
virtual void anchor();
96102

97103
RISCVProcFamilyEnum RISCVProcFamily = Others;
98104
RISCVVRGatherCostModelEnum RISCVVRGatherCostModel = Quadratic;
105+
RISCVZicfilpCFISchemeEnum RISCVZicfilpCFIScheme = ZicfilpDisabled;
99106

100107
#define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \
101108
bool ATTRIBUTE = DEFAULT;
@@ -205,6 +212,13 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
205212
return HasStdExtZicond || HasVendorXVentanaCondOps;
206213
}
207214

215+
RISCVZicfilpCFISchemeEnum getZicfilpCFIScheme() const {
216+
return RISCVZicfilpCFIScheme;
217+
}
218+
bool hasZicfilpCFI() const {
219+
return getZicfilpCFIScheme() != ZicfilpDisabled;
220+
}
221+
208222
bool hasConditionalMoveFusion() const {
209223
// Do we support fusing a branch+mv or branch+c.mv as a conditional move.
210224
return (hasConditionalCompressedMoveFusion() && hasStdExtZca()) ||

0 commit comments

Comments
 (0)