diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h --- a/llvm/lib/Target/RISCV/RISCVISelLowering.h +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -147,6 +147,13 @@ bool shouldExtendTypeInLibCall(EVT Type) const override; + /// Returns the register with the specified architectural or ABI name. This + /// method is necessary to lower the llvm.read_register.* and + /// llvm.write_register.* intrinsics. Allocatable registers must be reserved + /// with the clang -ffixed-xX flag for access to be allowed. + Register getRegisterByName(const char *RegName, EVT VT, + const MachineFunction &MF) const override; + private: void analyzeInputArgs(MachineFunction &MF, CCState &CCInfo, const SmallVectorImpl &Ins, diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -2894,3 +2894,22 @@ return true; } + +#define GET_REGISTER_MATCHER +#include "RISCVGenAsmMatcher.inc" + +Register +RISCVTargetLowering::getRegisterByName(const char *RegName, EVT VT, + const MachineFunction &MF) const { + Register Reg = MatchRegisterAltName(RegName); + if (Reg == RISCV::NoRegister) + Reg = MatchRegisterName(RegName); + if (Reg == RISCV::NoRegister) + report_fatal_error( + Twine("Invalid register name \"" + StringRef(RegName) + "\".")); + BitVector ReservedRegs = Subtarget.getRegisterInfo()->getReservedRegs(MF); + if (!ReservedRegs.test(Reg) && !Subtarget.isRegisterReservedByUser(Reg)) + report_fatal_error(Twine("Trying to obtain non-reserved register \"" + + StringRef(RegName) + "\".")); + return Reg; +} diff --git a/llvm/test/CodeGen/RISCV/get-register-invalid.ll b/llvm/test/CodeGen/RISCV/get-register-invalid.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/get-register-invalid.ll @@ -0,0 +1,12 @@ +; RUN: not llc < %s -mtriple=riscv32 2>&1 | FileCheck %s + +define i32 @get_invalid_reg() nounwind { +entry: +; CHECK: Invalid register name "notareg". + %reg = call i32 @llvm.read_register.i32(metadata !0) + ret i32 %reg +} + +declare i32 @llvm.read_register.i32(metadata) nounwind + +!0 = !{!"notareg\00"} diff --git a/llvm/test/CodeGen/RISCV/get-register-noreserve.ll b/llvm/test/CodeGen/RISCV/get-register-noreserve.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/get-register-noreserve.ll @@ -0,0 +1,38 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=riscv32 | FileCheck %s + +define i32 @get_stack() nounwind { +; CHECK-LABEL: get_stack: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mv a0, sp +; CHECK-NEXT: ret +entry: + %sp = call i32 @llvm.read_register.i32(metadata !0) + ret i32 %sp +} + +define void @set_stack(i32 %val) nounwind { +; CHECK-LABEL: set_stack: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mv sp, a0 +; CHECK-NEXT: ret +entry: + call void @llvm.write_register.i32(metadata !0, i32 %val) + ret void +} + +define i32 @get_tp_arch_name() nounwind { +; CHECK-LABEL: get_tp_arch_name: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: mv a0, tp +; CHECK-NEXT: ret +entry: + %sp = call i32 @llvm.read_register.i32(metadata !1) + ret i32 %sp +} + +declare i32 @llvm.read_register.i32(metadata) nounwind +declare void @llvm.write_register.i32(metadata, i32) nounwind + +!0 = !{!"sp\00"} +!1 = !{!"x4\00"} diff --git a/llvm/test/CodeGen/RISCV/get-register-reserve.ll b/llvm/test/CodeGen/RISCV/get-register-reserve.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/get-register-reserve.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: not llc < %s -mtriple=riscv32 -mattr +reserve-x8 2>&1 \ +; RUN: | FileCheck -check-prefix=NO-RESERVE-A1 %s +; RUN: not llc < %s -mtriple=riscv32 -mattr +reserve-x11 2>&1 \ +; RUN: | FileCheck -check-prefix=NO-RESERVE-FP %s +; RUN: llc < %s -mtriple=riscv32 -mattr +reserve-x8 -mattr +reserve-x11 \ +; RUN: | FileCheck -check-prefix=RESERVE %s + +define i32 @get_reg_a1() nounwind { +; NO-RESERVE-A1: Trying to obtain non-reserved register "a1". +; RESERVE-LABEL: get_reg_a1: +; RESERVE: # %bb.0: # %entry +; RESERVE-NEXT: mv a0, a1 +; RESERVE-NEXT: ret +entry: + %a1 = call i32 @llvm.read_register.i32(metadata !0) + ret i32 %a1 +} + +define i32 @get_reg_fp() nounwind { +; NO-RESERVE-FP: Trying to obtain non-reserved register "fp". +; RESERVE-LABEL: get_reg_fp: +; RESERVE: # %bb.0: # %entry +; RESERVE-NEXT: mv a0, s0 +; RESERVE-NEXT: ret +entry: + %fp = call i32 @llvm.read_register.i32(metadata !1) + ret i32 %fp +} + +declare i32 @llvm.read_register.i32(metadata) nounwind + +!0 = !{!"a1\00"} +!1 = !{!"fp\00"}