diff --git a/clang/include/clang/Basic/BuiltinsLoongArch.def b/clang/include/clang/Basic/BuiltinsLoongArch.def new file mode 100644 --- /dev/null +++ b/clang/include/clang/Basic/BuiltinsLoongArch.def @@ -0,0 +1,23 @@ +//==- BuiltinsLoongArch.def - LoongArch Builtin function database -- C++ -*-==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the LoongArch-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +#if defined(BUILTIN) && !defined(TARGET_BUILTIN) +# define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) BUILTIN(ID, TYPE, ATTRS) +#endif + +// TODO: Support more builtins. +// TODO: Added feature constraints. +TARGET_BUILTIN(__builtin_loongarch_dbar, "vIUi", "nc", "") + +#undef BUILTIN +#undef TARGET_BUILTIN diff --git a/clang/include/clang/Basic/TargetBuiltins.h b/clang/include/clang/Basic/TargetBuiltins.h --- a/clang/include/clang/Basic/TargetBuiltins.h +++ b/clang/include/clang/Basic/TargetBuiltins.h @@ -151,6 +151,16 @@ }; } // namespace RISCV + /// LoongArch builtins + namespace LoongArch { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin - 1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsLoongArch.def" + LastTSBuiltin + }; + } // namespace LoongArch + /// Flags to identify the types for overloaded Neon builtins. /// /// These must be kept in sync with the flags in utils/TableGen/NeonEmitter.h. diff --git a/clang/include/clang/module.modulemap b/clang/include/clang/module.modulemap --- a/clang/include/clang/module.modulemap +++ b/clang/include/clang/module.modulemap @@ -42,6 +42,7 @@ textual header "Basic/BuiltinsHexagon.def" textual header "Basic/BuiltinsHexagonDep.def" textual header "Basic/BuiltinsHexagonMapCustomDep.def" + textual header "Basic/BuiltinsLoongArch.def" textual header "Basic/BuiltinsMips.def" textual header "Basic/BuiltinsNEON.def" textual header "Basic/BuiltinsNVPTX.def" diff --git a/clang/lib/Basic/Targets/LoongArch.h b/clang/lib/Basic/Targets/LoongArch.h --- a/clang/lib/Basic/Targets/LoongArch.h +++ b/clang/lib/Basic/Targets/LoongArch.h @@ -26,6 +26,7 @@ std::string ABI; bool HasFeatureD; bool HasFeatureF; + static const Builtin::Info BuiltinInfo[]; public: LoongArchTargetInfo(const llvm::Triple &Triple, const TargetOptions &) diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp --- a/clang/lib/Basic/Targets/LoongArch.cpp +++ b/clang/lib/Basic/Targets/LoongArch.cpp @@ -160,9 +160,17 @@ } } +const Builtin::Info LoongArchTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE}, +#include "clang/Basic/BuiltinsLoongArch.def" +}; + ArrayRef LoongArchTargetInfo::getTargetBuiltins() const { - // TODO: To be implemented in future. - return {}; + return llvm::makeArrayRef(BuiltinInfo, clang::LoongArch::LastTSBuiltin - + Builtin::FirstTSBuiltin); } bool LoongArchTargetInfo::handleTargetFeatures( diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -41,6 +41,7 @@ #include "llvm/IR/IntrinsicsARM.h" #include "llvm/IR/IntrinsicsBPF.h" #include "llvm/IR/IntrinsicsHexagon.h" +#include "llvm/IR/IntrinsicsLoongArch.h" #include "llvm/IR/IntrinsicsNVPTX.h" #include "llvm/IR/IntrinsicsPowerPC.h" #include "llvm/IR/IntrinsicsR600.h" @@ -5447,6 +5448,9 @@ case llvm::Triple::riscv32: case llvm::Triple::riscv64: return CGF->EmitRISCVBuiltinExpr(BuiltinID, E, ReturnValue); + case llvm::Triple::loongarch32: + case llvm::Triple::loongarch64: + return CGF->EmitLoongArchBuiltinExpr(BuiltinID, E); default: return nullptr; } @@ -19618,3 +19622,27 @@ llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes); return Builder.CreateCall(F, Ops, ""); } + +Value *CodeGenFunction::EmitLoongArchBuiltinExpr(unsigned BuiltinID, + const CallExpr *E) { + SmallVector Ops; + + for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) + Ops.push_back(EmitScalarExpr(E->getArg(i))); + + Intrinsic::ID ID = Intrinsic::not_intrinsic; + + switch (BuiltinID) { + default: + llvm_unreachable("unexpected builtin ID."); + case LoongArch::BI__builtin_loongarch_dbar: + ID = Intrinsic::loongarch_dbar; + break; + // TODO: Support more Intrinsics. + } + + assert(ID != Intrinsic::not_intrinsic); + + llvm::Function *F = CGM.getIntrinsic(ID); + return Builder.CreateCall(F, Ops); +} diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4262,6 +4262,7 @@ llvm::Value *EmitHexagonBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitRISCVBuiltinExpr(unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue); + llvm::Value *EmitLoongArchBuiltinExpr(unsigned BuiltinID, const CallExpr *E); void ProcessOrderScopeAMDGCN(llvm::Value *Order, llvm::Value *Scope, llvm::AtomicOrdering &AO, llvm::SyncScope::ID &SSID); diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -75,6 +75,10 @@ ${hlsl_subdir_files} ) +set(loongarch_files + larchintrin.h + ) + set(mips_msa_files msa.h ) @@ -233,6 +237,7 @@ ${cuda_files} ${hexagon_files} ${hip_files} + ${loongarch_files} ${mips_msa_files} ${opencl_files} ${ppc_files} @@ -412,6 +417,7 @@ add_header_target("cuda-resource-headers" "${cuda_files};${cuda_wrapper_files}") add_header_target("hexagon-resource-headers" "${hexagon_files}") add_header_target("hip-resource-headers" "${hip_files}") +add_header_target("loongarch-resource-headers" "${loongarch_files}") add_header_target("mips-resource-headers" "${mips_msa_files}") add_header_target("ppc-resource-headers" "${ppc_files};${ppc_wrapper_files}") add_header_target("ppc-htm-resource-headers" "${ppc_htm_files}") @@ -502,6 +508,12 @@ EXCLUDE_FROM_ALL COMPONENT hip-resource-headers) +install( + FILES ${loongarch_files} + DESTINATION ${header_install_dir} + EXCLUDE_FROM_ALL + COMPONENT loongarch-resource-headers) + install( FILES ${mips_msa_files} DESTINATION ${header_install_dir} diff --git a/clang/lib/Headers/larchintrin.h b/clang/lib/Headers/larchintrin.h new file mode 100644 --- /dev/null +++ b/clang/lib/Headers/larchintrin.h @@ -0,0 +1,22 @@ +/*===------------ larchintrin.h - LoongArch intrinsics ---------------------=== + * + * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * See https://llvm.org/LICENSE.txt for license information. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef _LOONGARCH_BASE_INTRIN_H +#define _LOONGARCH_BASE_INTRIN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define __dbar(/*ui15*/ _1) __builtin_loongarch_dbar((_1)) + +#ifdef __cplusplus +} +#endif +#endif /* _LOONGARCH_BASE_INTRIN_H */ diff --git a/clang/test/CodeGen/LoongArch/intrinsic.c b/clang/test/CodeGen/LoongArch/intrinsic.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/LoongArch/intrinsic.c @@ -0,0 +1,22 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple loongarch32 -emit-llvm %s -o - \ +// RUN: | FileCheck %s -check-prefix=LA32 +// RUN: %clang_cc1 -triple loongarch64 -emit-llvm %s -o - \ +// RUN: | FileCheck %s -check-prefix=LA64 + +#include + +// LA32-LABEL: @dbar( +// LA32-NEXT: entry: +// LA32-NEXT: call void @llvm.loongarch.dbar(i32 0) +// LA32-NEXT: ret void +// +// LA64-LABEL: @dbar( +// LA64-NEXT: entry: +// LA64-NEXT: call void @llvm.loongarch.dbar(i32 0) +// LA64-NEXT: ret void +// +void dbar() { + return __builtin_loongarch_dbar(0); +} + diff --git a/llvm/include/llvm/IR/IntrinsicsLoongArch.td b/llvm/include/llvm/IR/IntrinsicsLoongArch.td --- a/llvm/include/llvm/IR/IntrinsicsLoongArch.td +++ b/llvm/include/llvm/IR/IntrinsicsLoongArch.td @@ -45,4 +45,6 @@ // @llvm.loongarch.masked.cmpxchg.i64.

( // ptr addr, grlen cmpval, grlen newval, grlen mask, grlenimm ordering) defm int_loongarch_masked_cmpxchg : MaskedAtomicRMWFiveOpIntrinsics; + +def int_loongarch_dbar : Intrinsic<[], [llvm_i32_ty]>; } // TargetPrefix = "loongarch" diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h @@ -56,6 +56,9 @@ REVB_2W, BITREV_4B, BITREV_W, + + // Intrinsic operations + DBAR, }; } // end namespace LoongArchISD @@ -174,6 +177,7 @@ SDValue lowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG) const; SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const; SDValue lowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; + SDValue lowerINTRINSIC_VOID(SDValue Op, SelectionDAG &DAG) const; SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -60,6 +60,7 @@ setOperationAction(ISD::CTPOP, GRLenVT, Expand); setOperationAction(ISD::DEBUGTRAP, MVT::Other, Legal); setOperationAction(ISD::TRAP, MVT::Other, Legal); + setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom); setOperationAction({ISD::GlobalAddress, ISD::BlockAddress, ISD::ConstantPool, ISD::JumpTable}, @@ -88,6 +89,7 @@ setOperationAction(ISD::ROTL, MVT::i32, Custom); setOperationAction(ISD::CTTZ, MVT::i32, Custom); setOperationAction(ISD::CTLZ, MVT::i32, Custom); + setOperationAction(ISD::INTRINSIC_VOID, MVT::i32, Custom); if (Subtarget.hasBasicF() && !Subtarget.hasBasicD()) setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom); if (Subtarget.hasBasicF()) @@ -208,6 +210,8 @@ return lowerGlobalTLSAddress(Op, DAG); case ISD::INTRINSIC_WO_CHAIN: return lowerINTRINSIC_WO_CHAIN(Op, DAG); + case ISD::INTRINSIC_VOID: + return lowerINTRINSIC_VOID(Op, DAG); case ISD::BlockAddress: return lowerBlockAddress(Op, DAG); case ISD::JumpTable: @@ -552,6 +556,38 @@ } } +SDValue LoongArchTargetLowering::lowerINTRINSIC_VOID(SDValue Op, + SelectionDAG &DAG) const { + SDLoc DL(Op); + MVT GRLenVT = Subtarget.getGRLenVT(); + + switch (Op.getConstantOperandVal(1)) { + default: + // TODO: Add more Intrinsics. + return SDValue(); + case Intrinsic::loongarch_dbar: { + SDValue Op0 = Op.getOperand(0); + SDValue Op2 = Op.getOperand(2); + if (!isa(Op2)) { + DAG.getContext()->emitError("argument to '__builtin_loongarch_dbar' must " + "be a constant integer"); + return Op.getOperand(0); + } + unsigned Imm = cast(Op2)->getZExtValue(); + if (!isUInt<15>(Imm)) { + DAG.getContext()->emitError( + "argument to '__builtin_loongarch_dbar' out of range"); + return Op0; + } + + if (GRLenVT == MVT::i32) + return Op; + return DAG.getNode(LoongArchISD::DBAR, DL, MVT::Other, Op0, + DAG.getConstant(Imm, DL, GRLenVT)); + } + } +} + SDValue LoongArchTargetLowering::lowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); @@ -1275,6 +1311,7 @@ NODE_NAME_CASE(ROTL_W) NODE_NAME_CASE(CLZ_W) NODE_NAME_CASE(CTZ_W) + NODE_NAME_CASE(DBAR) } #undef NODE_NAME_CASE return nullptr; diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td @@ -35,6 +35,8 @@ SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisInt<2>, SDTCisSameAs<2, 3> ]>; +def SDT_LoongArchDBAR : SDTypeProfile<0, 1, [SDTCisVT<0, GRLenVT>]>; + // TODO: Add LoongArch specific DAG Nodes // Target-independent nodes, but with target-specific formats. def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_CallSeqStart, @@ -63,6 +65,8 @@ def loongarch_bitrev_w : SDNode<"LoongArchISD::BITREV_W", SDTUnaryOp>; def loongarch_clzw : SDNode<"LoongArchISD::CLZ_W", SDTIntBitCountUnaryOp>; def loongarch_ctzw : SDNode<"LoongArchISD::CTZ_W", SDTIntBitCountUnaryOp>; +def loongarch_dbar : SDNode<"LoongArchISD::DBAR", SDT_LoongArchDBAR, + [SDNPHasChain, SDNPSideEffect]>; //===----------------------------------------------------------------------===// // Operand and SDNode transformation definitions. @@ -130,7 +134,8 @@ let ParserMatchClass = UImmAsmOperand<14>; } -def uimm15 : Operand { +def uimm15 : Operand, + ImmLeaf (Imm);}]> { let ParserMatchClass = UImmAsmOperand<15>; } @@ -1304,6 +1309,16 @@ (PseudoAtomicLoadXor32 GPR:$incr, GPR:$addr)>; } // Predicates = [IsLA32] +/// Intrinsics + +let Predicates = [IsLA32] in { +def : Pat<(int_loongarch_dbar uimm15:$imm15), (DBAR uimm15:$imm15)>; +} // Predicates = [IsLA32] + +let Predicates = [IsLA64] in { +def : Pat<(loongarch_dbar uimm15:$imm15), (DBAR uimm15:$imm15)>; +} // Predicates = [IsLA64] + /// Other pseudo-instructions // Pessimistically assume the stack pointer will be clobbered diff --git a/llvm/test/CodeGen/LoongArch/intrinsic-error.ll b/llvm/test/CodeGen/LoongArch/intrinsic-error.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/intrinsic-error.ll @@ -0,0 +1,18 @@ +; RUN: not llc --mtriple=loongarch32 --disable-verify < %s 2>&1 | FileCheck %s +; RUN: not llc --mtriple=loongarch64 --disable-verify < %s 2>&1 | FileCheck %s + +define void @dbar_not_constant(i32 %x) nounwind { +; CHECK: argument to '__builtin_loongarch_dbar' must be a constant integer +entry: + call void @llvm.loongarch.dbar(i32 %x) + ret void +} + +define void @dbar_imm_out_of_range() nounwind { +; CHECK: argument to '__builtin_loongarch_dbar' out of range +entry: + call void @llvm.loongarch.dbar(i32 32769) + ret void +} + +declare void @llvm.loongarch.dbar(i32) diff --git a/llvm/test/CodeGen/LoongArch/intrinsic.ll b/llvm/test/CodeGen/LoongArch/intrinsic.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/intrinsic.ll @@ -0,0 +1,15 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc --mtriple=loongarch32 < %s | FileCheck %s +; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s + +declare void @llvm.loongarch.dbar(i32) + +define void @foo() nounwind { +; CHECK-LABEL: foo: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: dbar 0 +; CHECK-NEXT: ret +entry: + call void @llvm.loongarch.dbar(i32 0) + ret void +}