Skip to content

[CHERIOT] Use capability registers to store f64 values. #190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: cheriot
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions llvm/lib/Target/RISCV/RISCVCallingConv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,14 @@ bool llvm::CC_RISCV(unsigned ValNo, MVT ValVT, MVT LocVT,
}
}

// Cheriot uses GPCR without a bitcast when possible.
if (LocVT == MVT::f64 && Subtarget.hasVendorXCheriot() && !IsPureCapVarArgs) {
if (MCRegister Reg = State.AllocateReg(ArgGPCRs)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
return false;
}
}

// FP smaller than XLen, uses custom GPR.
if (LocVT == MVT::f16 || LocVT == MVT::bf16 ||
(LocVT == MVT::f32 && XLen == 64)) {
Expand Down
58 changes: 55 additions & 3 deletions llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
addRegisterClass(CapType, &RISCV::GPCRRegClass);
}

if (Subtarget.hasVendorXCheriot()) {
// Cheriot holds f64's in capability registers.
addRegisterClass(MVT::f64, &RISCV::GPCRRegClass);
}

static const MVT::SimpleValueType BoolVecVTs[] = {
MVT::nxv1i1, MVT::nxv2i1, MVT::nxv4i1, MVT::nxv8i1,
MVT::nxv16i1, MVT::nxv32i1, MVT::nxv64i1};
Expand Down Expand Up @@ -680,6 +685,20 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
setLibcallName(RTLIB::MEMSET, "memset");
}

if (Subtarget.hasVendorXCheriot()) {
setOperationAction(ISD::ConstantFP, MVT::f64, Custom);

static const unsigned CheriotF64ExpandOps[] = {
ISD::FMINNUM, ISD::FMAXNUM, ISD::FADD, ISD::FSUB,
ISD::FMUL, ISD::FMA, ISD::FDIV, ISD::FSQRT,
ISD::FCEIL, ISD::FTRUNC, ISD::FFLOOR, ISD::FROUND,
ISD::FROUNDEVEN, ISD::FRINT, ISD::FNEARBYINT, ISD::IS_FPCLASS,
ISD::SETCC, ISD::FMAXIMUM, ISD::FMINIMUM, ISD::STRICT_FADD,
ISD::STRICT_FSUB, ISD::STRICT_FMUL, ISD::STRICT_FDIV, ISD::STRICT_FSQRT,
ISD::STRICT_FMA};
setOperationAction(CheriotF64ExpandOps, MVT::f64, Expand);
}

// TODO: On M-mode only targets, the cycle[h]/time[h] CSR may not be present.
// Unfortunately this can't be determined just from the ISA naming string.
setOperationAction(ISD::READCYCLECOUNTER, MVT::i64,
Expand Down Expand Up @@ -6145,11 +6164,44 @@ static SDValue lowerConstant(SDValue Op, SelectionDAG &DAG,
return SDValue();
}

SDValue RISCVTargetLowering::lowerConstantFP(SDValue Op,
SelectionDAG &DAG) const {
SDValue
RISCVTargetLowering::lowerConstantFP(SDValue Op, SelectionDAG &DAG,
const RISCVSubtarget &Subtarget) const {
MVT VT = Op.getSimpleValueType();
const APFloat &Imm = cast<ConstantFPSDNode>(Op)->getValueAPF();

if (Subtarget.hasVendorXCheriot()) {
// Cheriot needs to custom lower f64 immediates using csethigh
if (VT != MVT::f64)
return Op;

SDLoc DL(Op);
uint64_t Val = Imm.bitcastToAPInt().getLimitedValue();

// Materialize 0.0 as cnull
if (Val == 0)
return DAG.getRegister(getNullCapabilityRegister(), MVT::f64);

// Otherwise, materialize the low part into a 32-bit register.
auto Lo = DAG.getConstant(Val & 0xFFFFFFFF, DL, MVT::i32);
auto LoAsCap = DAG.getTargetInsertSubreg(RISCV::sub_cap_addr, DL, MVT::c64,
DAG.getUNDEF(MVT::f64), Lo);

// The high half of a capability register is zeroed by integer ops,
// so if we wanted a zero high half then we are done.
if (Val >> 32 == 0)
return DAG.getBitcast(MVT::f64, LoAsCap);

// Otherwise, materialize the high half and use csethigh to combine the two
// halve.
auto Hi = DAG.getConstant(Val >> 32, DL, MVT::i32);
auto Cap = DAG.getNode(
ISD::INTRINSIC_WO_CHAIN, DL, MVT::c64,
DAG.getTargetConstant(Intrinsic::cheri_cap_high_set, DL, MVT::i32),
LoAsCap, Hi);
return DAG.getBitcast(MVT::f64, Cap);
}

// Can this constant be selected by a Zfa FLI instruction?
bool Negate = false;
int Index = getLegalZfaFPImm(Imm, VT);
Expand Down Expand Up @@ -6799,7 +6851,7 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
case ISD::Constant:
return lowerConstant(Op, DAG, Subtarget);
case ISD::ConstantFP:
return lowerConstantFP(Op, DAG);
return lowerConstantFP(Op, DAG, Subtarget);
case ISD::SELECT:
return lowerSELECT(Op, DAG);
case ISD::BRCOND:
Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/RISCV/RISCVISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,8 @@ class RISCVTargetLowering : public TargetLowering {
SelectionDAG &DAG) const;
SDValue getTLSDescAddr(GlobalAddressSDNode *N, SelectionDAG &DAG) const;

SDValue lowerConstantFP(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerConstantFP(SDValue Op, SelectionDAG &DAG,
const RISCVSubtarget &Subtarget) const;
SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerConstantPool(SDValue Op, SelectionDAG &DAG) const;
Expand Down
115 changes: 69 additions & 46 deletions llvm/lib/Target/RISCV/RISCVInstrInfoXCheri.td
Original file line number Diff line number Diff line change
Expand Up @@ -1451,7 +1451,7 @@ def : PatGpcrUimm12<int_cheri_bounded_stack_cap, CSetBoundsImm>;
def : PatGpcrGpr<int_cheri_bounded_stack_cap_dynamic, CSetBounds>;
def : PatGpcrUimm12<int_cheri_bounded_stack_cap_dynamic, CSetBoundsImm>;

def : Pat<(CapFrameAddrRegImm GPCR:$rs1, simm12:$imm12),
def : Pat<(CapFrameAddrRegImm(cPTR GPCR:$rs1), simm12:$imm12),
(CIncOffsetImm GPCR:$rs1, simm12:$imm12)>;

/// Pointer-Arithmetic Instructions
Expand All @@ -1463,14 +1463,15 @@ def : Pat<(XLenVT (int_cheri_cap_diff GPCR:$cs1, GPCR:$cs2)),
(XLenVT (EXTRACT_SUBREG GPCR:$cs2, sub_cap_addr)))>;

let Predicates = [IsPureCapABI] in {
def : Pat<(inttoptr (XLenVT GPR:$rs2)), (CIncOffset C0, GPR:$rs2)>;
def : Pat<(inttoptr simm12:$imm12), (CIncOffsetImm C0, simm12:$imm12)>;
def : Pat<(XLenVT (ptrtoint GPCR:$rs1)), (PseudoCGetAddr GPCR:$rs1)>;
def : Pat<(inttoptr(XLenVT GPR:$rs2)), (cPTR(CIncOffset(cPTR C0), GPR:$rs2))>;
def : Pat<(inttoptr simm12:$imm12), (cPTR(CIncOffsetImm(cPTR C0),
simm12:$imm12))>;
def : Pat<(XLenVT(ptrtoint(cPTR GPCR:$rs1))), (PseudoCGetAddr GPCR:$rs1)>;
}

/// Null Capability Patterns

def : Pat<(inttoptr (XLenVT 0)), (CLenVT (COPY C0))>;
def : Pat<(inttoptr(XLenVT 0)), (CLenVT(COPY(cPTR C0)))>;
def : Pat<(ptrtoint (CLenVT (inttoptr (XLenVT 0)))),
(XLenVT (COPY (XLenVT X0)))>;

Expand All @@ -1481,26 +1482,31 @@ def : Pat<(ptrtoint (CLenVT (inttoptr (XLenVT 0)))),
// * Break untagged < tagged semantics
// * Can't implement exact equality
class CheriSetCCPatGpcrGpcr<PatFrag CondOp, dag GprGprDag>
: Pat<(XLenVT (CondOp GPCR:$cs1, GPCR:$cs2)),
(OutPatFrag<(ops node:$rs1, node:$rs2), GprGprDag>
(XLenVT (EXTRACT_SUBREG GPCR:$cs1, sub_cap_addr)),
(XLenVT (EXTRACT_SUBREG GPCR:$cs2, sub_cap_addr)))>;
: Pat<(XLenVT(CondOp(cPTR GPCR:$cs1), (cPTR GPCR:$cs2))),
(OutPatFrag<(ops node:$rs1, node:$rs2), GprGprDag>(XLenVT
(EXTRACT_SUBREG GPCR:$cs1, sub_cap_addr)),
(XLenVT(EXTRACT_SUBREG GPCR:$cs2, sub_cap_addr)))>;

multiclass CheriSetCCPatGpcrImm<PatFrag CondOp, Operand ImmTy, dag GprImmDag> {
def : Pat<(XLenVT (CondOp GPCR:$cs1, (inttoptr ImmTy:$imm12))),
(OutPatFrag<(ops node:$rs1, node:$imm12), GprImmDag>
(XLenVT (EXTRACT_SUBREG GPCR:$cs1, sub_cap_addr)), ImmTy:$imm12)>;
def : Pat<(XLenVT (CondOp GPCR:$cs1, (cptradd (inttoptr (XLenVT 0)), ImmTy:$imm12))),
(OutPatFrag<(ops node:$rs1, node:$imm12), GprImmDag>
(XLenVT (EXTRACT_SUBREG GPCR:$cs1, sub_cap_addr)), ImmTy:$imm12)>;
def : Pat<(XLenVT (CondOp GPCR:$cs1,
(int_cheri_cap_offset_set (inttoptr (XLenVT 0)), ImmTy:$imm12))),
(OutPatFrag<(ops node:$rs1, node:$imm12), GprImmDag>
(XLenVT (EXTRACT_SUBREG GPCR:$cs1, sub_cap_addr)), ImmTy:$imm12)>;
def : Pat<(XLenVT (CondOp GPCR:$cs1,
(int_cheri_cap_address_set (inttoptr (XLenVT 0)), ImmTy:$imm12))),
(OutPatFrag<(ops node:$rs1, node:$imm12), GprImmDag>
(XLenVT (EXTRACT_SUBREG GPCR:$cs1, sub_cap_addr)), ImmTy:$imm12)>;
def : Pat<(XLenVT(CondOp(cPTR GPCR:$cs1), (inttoptr ImmTy:$imm12))),
(OutPatFrag<(ops node:$rs1, node:$imm12), GprImmDag>(XLenVT
(EXTRACT_SUBREG GPCR:$cs1, sub_cap_addr)),
ImmTy:$imm12)>;
def : Pat<(XLenVT(CondOp(cPTR GPCR:$cs1), (cptradd(inttoptr(XLenVT 0)),
ImmTy:$imm12))),
(OutPatFrag<(ops node:$rs1, node:$imm12), GprImmDag>(XLenVT
(EXTRACT_SUBREG GPCR:$cs1, sub_cap_addr)),
ImmTy:$imm12)>;
def : Pat<(XLenVT(CondOp(cPTR GPCR:$cs1),
(int_cheri_cap_offset_set(inttoptr(XLenVT 0)), ImmTy:$imm12))),
(OutPatFrag<(ops node:$rs1, node:$imm12), GprImmDag>(XLenVT
(EXTRACT_SUBREG GPCR:$cs1, sub_cap_addr)),
ImmTy:$imm12)>;
def : Pat<(XLenVT(CondOp(cPTR GPCR:$cs1),
(int_cheri_cap_address_set(inttoptr(XLenVT 0)), ImmTy:$imm12))),
(OutPatFrag<(ops node:$rs1, node:$imm12), GprImmDag>(XLenVT
(EXTRACT_SUBREG GPCR:$cs1, sub_cap_addr)),
ImmTy:$imm12)>;
}

multiclass CheriSetCCPatGpcrSimm12<PatFrag CondOp, dag GprImmDag>
Expand All @@ -1510,9 +1516,9 @@ multiclass CheriSetCCPatGpcrSimm12Plus1<PatFrag CondOp, dag GprImmDag>
: CheriSetCCPatGpcrImm<CondOp, simm12_plus1, GprImmDag>;

class CheriSetCCPatGpcrNull<PatFrag CondOp, dag GprDag>
: Pat<(XLenVT (CondOp GPCR:$cs1, (inttoptr (XLenVT 0)))),
(OutPatFrag<(ops node:$rs1), GprDag>
(XLenVT (EXTRACT_SUBREG GPCR:$cs1, sub_cap_addr)))>;
: Pat<(XLenVT(CondOp(cPTR GPCR:$cs1), (inttoptr(XLenVT 0)))),
(OutPatFrag<(ops node:$rs1), GprDag>(XLenVT(EXTRACT_SUBREG GPCR:$cs1,
sub_cap_addr)))>;

class Swap<PatFrag BinFrag>
: PatFrag<(ops node:$a, node:$b), (BinFrag $b, $a)>;
Expand Down Expand Up @@ -1555,11 +1561,10 @@ defm Select_GPCR : SelectCC_GPR_rrirr<GPCR, CLenVT>;
// No dedicated instructions; see above

class CheriBccPat<PatFrag CondOp, RVInstB Inst>
: Pat<(brcond (XLenVT (CondOp GPCR:$rs1, GPCR:$rs2)), bb:$imm12),
(Inst
(XLenVT (EXTRACT_SUBREG GPCR:$rs1, sub_cap_addr)),
(XLenVT (EXTRACT_SUBREG GPCR:$rs2, sub_cap_addr)),
simm13_lsb0:$imm12)>;
: Pat<(brcond(XLenVT(CondOp(cPTR GPCR:$rs1), (cPTR GPCR:$rs2))), bb:$imm12),
(Inst(XLenVT(EXTRACT_SUBREG GPCR:$rs1, sub_cap_addr)),
(XLenVT(EXTRACT_SUBREG GPCR:$rs2, sub_cap_addr)),
simm13_lsb0:$imm12)>;

def : CheriBccPat<seteq, BEQ>;
def : CheriBccPat<setne, BNE>;
Expand All @@ -1569,11 +1574,10 @@ def : CheriBccPat<setult, BLTU>;
def : CheriBccPat<setuge, BGEU>;

class CheriBccSwapPat<PatFrag CondOp, RVInst InstBcc>
: Pat<(brcond (XLenVT (CondOp GPCR:$rs1, GPCR:$rs2)), bb:$imm12),
(InstBcc
(XLenVT (EXTRACT_SUBREG GPCR:$rs2, sub_cap_addr)),
(XLenVT (EXTRACT_SUBREG GPCR:$rs1, sub_cap_addr)),
simm13_lsb0:$imm12)>;
: Pat<(brcond(XLenVT(CondOp(cPTR GPCR:$rs1), (cPTR GPCR:$rs2))), bb:$imm12),
(InstBcc(XLenVT(EXTRACT_SUBREG GPCR:$rs2, sub_cap_addr)),
(XLenVT(EXTRACT_SUBREG GPCR:$rs1, sub_cap_addr)),
simm13_lsb0:$imm12)>;

def : CheriBccSwapPat<setgt, BLT>;
def : CheriBccSwapPat<setle, BGE>;
Expand All @@ -1587,15 +1591,18 @@ def : PatGpcrGpcr<riscv_cap_equal_exact, CSEQX, XLenVT>;

/// Special Capability Register Access Instructions

def : Pat<(int_cheri_ddc_get), (CSpecialRW SCR_DDC.Encoding, C0)>;
let Predicates = [HasCheri, IsPureCapABI] in
def : Pat<(int_cheri_stack_cap_get), (CLenVT (COPY C2))>;
def : Pat<(int_cheri_ddc_get), (CSpecialRW SCR_DDC.Encoding, (cPTR C0))>;
let Predicates = [HasCheri,
IsPureCapABI] in def : Pat<(int_cheri_stack_cap_get),
(CLenVT(COPY(cPTR C2)))>;

let Predicates = [HasCheri, IsCapMode] in
def : Pat<(int_cheri_pcc_get), (AUIPCC 0)>;

let Predicates = [HasCheri, NotCapMode] in
def : Pat<(int_cheri_pcc_get), (CSpecialRW SCR_PCC.Encoding, C0)>;
let Predicates = [HasCheri,
NotCapMode] in def : Pat<(int_cheri_pcc_get),
(CSpecialRW SCR_PCC.Encoding,
(cPTR C0))>;

/// Fast Register-Clearing Instructions

Expand Down Expand Up @@ -1824,13 +1831,14 @@ defm : PseudoCmpXchgPat<"atomic_cmp_swap_cap", PseudoCmpXchgCap, CLenVT, GPCR>;
/// Capability Mode Instructions

multiclass CheriLdPat<PatFrag LoadOp, RVInst Inst, ValueType ReturnVt = XLenVT> {
def : Pat<(ReturnVt (LoadOp (CapRegImm GPCR:$rs1, simm12:$imm12))),
def : Pat<(ReturnVt(LoadOp(CapRegImm(cPTR GPCR:$rs1), simm12:$imm12))),
(Inst GPCR:$rs1, simm12:$imm12)>;
}

multiclass CheriStPat<PatFrag StoreOp, RVInst Inst, RegisterClass StTy, ValueType StoreVt = XLenVT> {
def : Pat<(StoreOp (StoreVt StTy:$rs2), (CapRegImm GPCR:$rs1, simm12:$imm12)),
(Inst (StoreVt StTy:$rs2), GPCR:$rs1, simm12:$imm12)>;
def : Pat<(StoreOp(StoreVt StTy:$rs2), (CapRegImm(cPTR GPCR:$rs1),
simm12:$imm12)),
(Inst(StoreVt StTy:$rs2), GPCR:$rs1, simm12:$imm12)>;
}

multiclass CheriAtomicStPat<PatFrag StoreOp, RVInst Inst, RegisterClass StTy, ValueType StoreVt>
Expand Down Expand Up @@ -2287,6 +2295,11 @@ defm : CheriLdPat<load, CLC_128, CLenVT>;
defm : CheriStPat<store, CSC_128, GPCR, CLenVT>;
} // Predicates = [HasCheri, IsRV64, IsCapMode]

let Predicates = [HasCheri, HasCheriot, IsRV32, IsCapMode] in {
defm : CheriLdPat<load, CLC_64, f64>;
defm : CheriStPat<store, CSC_64, GPCR, f64>;
} // Predicates = [HasCheri, HasCheriot, IsRV32, IsCapMode]

//===----------------------------------------------------------------------===//
// Compress Instruction tablegen backend.
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -2429,7 +2442,17 @@ let Predicates = [HasCheri, IsRV32, IsCapMode, IsRVE] in {
let mayLoad = true, mayStore = false, hasSideEffects = false in
def PseudoCLLW : Pseudo<(outs GPCR:$dst), (ins bare_symbol:$src), [],
"cllc", "$dst, $src">;
def : Pat<(load (cPTR (load (iPTR globaladdr:$src)))),
def : Pat<(c64(load(cPTR(load(iPTR globaladdr:$src))))),
(PseudoCLLW bare_symbol:$src)>;
def : Pat<(f64(load(cPTR(load(iPTR globaladdr:$src))))),
(PseudoCLLW bare_symbol:$src)>;
} // Predicates = [HasCheri, IsRV32, IsCapMode, IsRVE]


// Cheriot stores f64 in cap registers, so bitcasting between f64 and c64
// is a no-op.
multiclass NopCapRegCast<ValueType Ty1, ValueType Ty2> {
def : Pat<(Ty1(bitconvert(Ty2 GPCR:$Val))), (Ty1 GPCR:$Val)>;
def : Pat<(Ty2(bitconvert(Ty1 GPCR:$Val))), (Ty2 GPCR:$Val)>;
}

let Predicates = [HasCheri, HasCheriot] in { defm : NopCapRegCast<c64, f64>; }
Loading