From eca62f92045ca8d2896a1e2ee2113056a13596ef Mon Sep 17 00:00:00 2001 From: gonglingqin Date: Thu, 24 Nov 2022 10:15:18 +0800 Subject: [PATCH] [LoongArch] Diagnose the behavior of reading and writing registers that do not conform to the hardware register size When reading or writing a register that does not conform to the size of a hardware register, an error message is generated instead of a compiler crash. Differential Revision: https://reviews.llvm.org/D138008 --- .../lib/Target/LoongArch/LoongArchISelLowering.cpp | 35 ++++++++++++++++++++++ llvm/lib/Target/LoongArch/LoongArchISelLowering.h | 1 + llvm/test/CodeGen/LoongArch/get-reg-error-la32.ll | 21 +++++++++++++ llvm/test/CodeGen/LoongArch/get-reg-error-la64.ll | 21 +++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 llvm/test/CodeGen/LoongArch/get-reg-error-la32.ll create mode 100644 llvm/test/CodeGen/LoongArch/get-reg-error-la64.ll diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp index d80d292..4f341c8 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -93,6 +93,8 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM, setOperationAction(ISD::CTLZ, MVT::i32, Custom); setOperationAction(ISD::INTRINSIC_VOID, MVT::i32, Custom); setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i32, Custom); + setOperationAction(ISD::READ_REGISTER, MVT::i32, Custom); + setOperationAction(ISD::WRITE_REGISTER, MVT::i32, Custom); if (Subtarget.hasBasicF() && !Subtarget.hasBasicD()) setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); if (Subtarget.hasBasicF()) @@ -118,6 +120,8 @@ LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM, } else { setOperationAction(ISD::BITREVERSE, MVT::i32, Legal); setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::i64, Custom); + setOperationAction(ISD::READ_REGISTER, MVT::i64, Custom); + setOperationAction(ISD::WRITE_REGISTER, MVT::i64, Custom); } static const ISD::CondCode FPCCToExpand[] = { @@ -244,10 +248,30 @@ SDValue LoongArchTargetLowering::LowerOperation(SDValue Op, return lowerFRAMEADDR(Op, DAG); case ISD::RETURNADDR: return lowerRETURNADDR(Op, DAG); + case ISD::WRITE_REGISTER: + return lowerWRITE_REGISTER(Op, DAG); } return SDValue(); } +SDValue LoongArchTargetLowering::lowerWRITE_REGISTER(SDValue Op, + SelectionDAG &DAG) const { + + if (Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i32) { + DAG.getContext()->emitError( + "On LA64, only 64-bit registers can be written."); + return Op.getOperand(0); + } + + if (!Subtarget.is64Bit() && Op.getOperand(2).getValueType() == MVT::i64) { + DAG.getContext()->emitError( + "On LA32, only 32-bit registers can be written."); + return Op.getOperand(0); + } + + return Op; +} + SDValue LoongArchTargetLowering::lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { if (!isa(Op.getOperand(0))) { @@ -927,6 +951,17 @@ void LoongArchTargetLowering::ReplaceNodeResults( } break; } + case ISD::READ_REGISTER: { + if (Subtarget.is64Bit()) + DAG.getContext()->emitError( + "On LA64, only 64-bit registers can be read."); + else + DAG.getContext()->emitError( + "On LA32, only 32-bit registers can be read."); + Results.push_back(DAG.getUNDEF(N->getValueType(0))); + Results.push_back(N->getOperand(0)); + break; + } } } diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h index 6f98e40..4f650fe 100644 --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h @@ -192,6 +192,7 @@ private: SDValue lowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const; SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerWRITE_REGISTER(SDValue Op, SelectionDAG &DAG) const; bool isFPImmLegal(const APFloat &Imm, EVT VT, bool ForCodeSize) const override; diff --git a/llvm/test/CodeGen/LoongArch/get-reg-error-la32.ll b/llvm/test/CodeGen/LoongArch/get-reg-error-la32.ll new file mode 100644 index 0000000..7440bfe --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/get-reg-error-la32.ll @@ -0,0 +1,21 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: not llc < %s --mtriple=loongarch32 2>&1 | FileCheck %s + +define i64 @read_sp() nounwind { +entry: +; CHECK: On LA32, only 32-bit registers can be read. + %a1 = call i64 @llvm.read_register.i64(metadata !0) + ret i64 %a1 +} + +define void @write_sp(i64 %val) nounwind { +entry: +; CHECK: On LA32, only 32-bit registers can be written. + call void @llvm.write_register.i64(metadata !0, i64 %val) + ret void +} + +declare i64 @llvm.read_register.i64(metadata) nounwind +declare void @llvm.write_register.i64(metadata, i64) nounwind + +!0 = !{!"$sp\00"} diff --git a/llvm/test/CodeGen/LoongArch/get-reg-error-la64.ll b/llvm/test/CodeGen/LoongArch/get-reg-error-la64.ll new file mode 100644 index 0000000..9312aa9 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/get-reg-error-la64.ll @@ -0,0 +1,21 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: not llc < %s --mtriple=loongarch64 2>&1 | FileCheck %s + +define i32 @read_sp() nounwind { +entry: +; CHECK: On LA64, only 64-bit registers can be read. + %a1 = call i32 @llvm.read_register.i32(metadata !0) + ret i32 %a1 +} + +define void @write_sp(i32 %val) nounwind { +entry: +; CHECK: On LA64, only 64-bit registers can be written. + call void @llvm.write_register.i32(metadata !0, i32 %val) + ret void +} + +declare i32 @llvm.read_register.i32(metadata) nounwind +declare void @llvm.write_register.i32(metadata, i32) nounwind + +!0 = !{!"$sp\00"} -- 2.7.4