diff --git a/src/llvm/include/llvm/IR/Intrinsics.td b/src/llvm/include/llvm/IR/Intrinsics.td index 64603d8ea03..7a2575377d6 100644 --- a/src/llvm/include/llvm/IR/Intrinsics.td +++ b/src/llvm/include/llvm/IR/Intrinsics.td @@ -1156,3 +1156,4 @@ include "llvm/IR/IntrinsicsBPF.td" include "llvm/IR/IntrinsicsSystemZ.td" include "llvm/IR/IntrinsicsWebAssembly.td" include "llvm/IR/IntrinsicsRISCV.td" +include "llvm/IR/IntrinsicsMSP430.td" diff --git a/src/llvm/include/llvm/IR/IntrinsicsMSP430.td b/src/llvm/include/llvm/IR/IntrinsicsMSP430.td new file mode 100644 index 00000000000..d663a6b8744 --- /dev/null +++ b/src/llvm/include/llvm/IR/IntrinsicsMSP430.td @@ -0,0 +1,21 @@ +//===- IntrinsicsMSP430.td - Defines MSP430 intrinsics -----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines all of the MSP430-specific intrinsics. +// +//===----------------------------------------------------------------------===// + +let TargetPrefix = "msp430" in { // All intrinsics start with "llvm.msp430." + def int_msp430_bic_saved_status : + Intrinsic<[llvm_i16_ty], [llvm_i16_ty], []>, + GCCBuiltin<"__bic_SR_register_on_exit">; + def int_msp430_bis_saved_status : + Intrinsic<[llvm_i16_ty], [llvm_i16_ty], []>, + GCCBuiltin<"__bis_SR_register_on_exit">; +} diff --git a/src/llvm/lib/Support/Triple.cpp b/src/llvm/lib/Support/Triple.cpp index 26d9327f620..57af42b7705 100644 --- a/src/llvm/lib/Support/Triple.cpp +++ b/src/llvm/lib/Support/Triple.cpp @@ -101,6 +101,8 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) { case mips64: case mips64el: return "mips"; + case msp430: return "msp430"; + case hexagon: return "hexagon"; case amdgcn: return "amdgcn"; diff --git a/src/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp b/src/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp index 3e706134afc..e69617ba01e 100644 --- a/src/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp +++ b/src/llvm/lib/Target/MSP430/MSP430ISelLowering.cpp @@ -146,6 +146,9 @@ MSP430TargetLowering::MSP430TargetLowering(const TargetMachine &TM, setOperationAction(ISD::VACOPY, MVT::Other, Expand); setOperationAction(ISD::JumpTable, MVT::i16, Custom); + // Custom lowering for some intrinsics + setOperationAction(ISD::INTRINSIC_W_CHAIN, MVT::Other, Custom); + // EABI Libcalls - EABI Section 6.2 const struct { const RTLIB::Libcall Op; @@ -349,6 +352,7 @@ SDValue MSP430TargetLowering::LowerOperation(SDValue Op, case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG); case ISD::VASTART: return LowerVASTART(Op, DAG); case ISD::JumpTable: return LowerJumpTable(Op, DAG); + case ISD::INTRINSIC_W_CHAIN: return LowerINTRINSIC_W_CHAIN(Op, DAG); default: llvm_unreachable("unimplemented operand"); } @@ -938,6 +942,55 @@ SDValue MSP430TargetLowering::LowerCallResult( return Chain; } +SDValue MSP430TargetLowering:: +LowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const { + unsigned IntNo = cast(Op.getOperand(1))->getZExtValue(); + switch (IntNo) { + default: + break; + case Intrinsic::msp430_bis_saved_status: + case Intrinsic::msp430_bic_saved_status: + MachineFunction &MF = DAG.getMachineFunction(); + MSP430MachineFunctionInfo *FuncInfo = + MF.getInfo(); + + int SavedSRFrameIndex = FuncInfo->getSavedSRIndex(); + if (SavedSRFrameIndex == 0) { + SavedSRFrameIndex = + MF.getFrameInfo().CreateFixedObject(/*Size*/ 2, /*Offset*/-2, true); + FuncInfo->setSavedSRIndex(SavedSRFrameIndex); + } + + MVT PtrVT = getPointerTy(DAG.getDataLayout()); + SDValue FI = DAG.getFrameIndex(SavedSRFrameIndex, PtrVT); + + SDValue Chain = Op->getOperand(0); + SDLoc DL(Op); + + // Load a saved copy of status register. + SDValue SR = + DAG.getLoad(MVT::i16, DL, Chain, FI, + MachinePointerInfo::getFixedStack(MF, SavedSRFrameIndex)); + + SDValue Result; + if (IntNo == Intrinsic::msp430_bis_saved_status) { + Result = DAG.getNode(ISD::OR, DL, MVT::i16, SR, Op->getOperand(2)); + } else { + // IntNo == Intrinsic::msp430_bic_saved_status + Result = DAG.getNOT(DL, Op->getOperand(2), MVT::i16); + Result = DAG.getNode(ISD::AND, DL, MVT::i16, SR, Result); + } + + // Store the result. + Chain = + DAG.getStore(SR.getValue(1), DL, Result, FI, + MachinePointerInfo::getFixedStack(MF, SavedSRFrameIndex)); + SDValue Ops[2] = { SR.getValue(0), Chain }; + return DAG.getMergeValues(Ops, DL); + } + return SDValue(); +} + SDValue MSP430TargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const { unsigned Opc = Op.getOpcode(); diff --git a/src/llvm/lib/Target/MSP430/MSP430ISelLowering.h b/src/llvm/lib/Target/MSP430/MSP430ISelLowering.h index 731bc140671..197fb964147 100644 --- a/src/llvm/lib/Target/MSP430/MSP430ISelLowering.h +++ b/src/llvm/lib/Target/MSP430/MSP430ISelLowering.h @@ -99,6 +99,7 @@ namespace llvm { SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const; SDValue LowerJumpTable(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const; SDValue getReturnAddressFrameIndex(SelectionDAG &DAG) const; TargetLowering::ConstraintType diff --git a/src/llvm/lib/Target/MSP430/MSP430MachineFunctionInfo.h b/src/llvm/lib/Target/MSP430/MSP430MachineFunctionInfo.h index fcaa8a1d6c7..fd1a68a9043 100644 --- a/src/llvm/lib/Target/MSP430/MSP430MachineFunctionInfo.h +++ b/src/llvm/lib/Target/MSP430/MSP430MachineFunctionInfo.h @@ -33,6 +33,10 @@ class MSP430MachineFunctionInfo : public MachineFunctionInfo { /// VarArgsFrameIndex - FrameIndex for start of varargs area. int VarArgsFrameIndex; + /// SavedSRFrameIndex - FrameIndex for saved copy of status register + /// (interrupt handlers only). + int SavedSRFrameIndex; + /// SRetReturnReg - Some subtargets require that sret lowering includes /// returning the value of the returned struct in a register. This field /// holds the virtual register into which the sret argument is passed. @@ -42,7 +46,8 @@ class MSP430MachineFunctionInfo : public MachineFunctionInfo { MSP430MachineFunctionInfo() : CalleeSavedFrameSize(0) {} explicit MSP430MachineFunctionInfo(MachineFunction &MF) - : CalleeSavedFrameSize(0), ReturnAddrIndex(0), SRetReturnReg(0) {} + : CalleeSavedFrameSize(0), ReturnAddrIndex(0), SavedSRFrameIndex(0), + SRetReturnReg(0) {} unsigned getCalleeSavedFrameSize() const { return CalleeSavedFrameSize; } void setCalleeSavedFrameSize(unsigned bytes) { CalleeSavedFrameSize = bytes; } @@ -53,6 +58,9 @@ class MSP430MachineFunctionInfo : public MachineFunctionInfo { int getRAIndex() const { return ReturnAddrIndex; } void setRAIndex(int Index) { ReturnAddrIndex = Index; } + int getSavedSRIndex() const { return SavedSRFrameIndex; } + void setSavedSRIndex(int Index) { SavedSRFrameIndex = Index; } + int getVarArgsFrameIndex() const { return VarArgsFrameIndex;} void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; } }; diff --git a/src/llvm/test/CodeGen/MSP430/bic_bis_saved_status.ll b/src/llvm/test/CodeGen/MSP430/bic_bis_saved_status.ll new file mode 100644 index 00000000000..a598351e77f --- /dev/null +++ b/src/llvm/test/CodeGen/MSP430/bic_bis_saved_status.ll @@ -0,0 +1,44 @@ +; RUN: llc < %s | FileCheck %s + +target datalayout = "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16" +target triple = "msp430-elf" + +define msp430_intrcc void @bis() #0 { +; CHECK-LABEL: bis: +; CHECK: bis #5, @r1 + %1 = call i16 @llvm.msp430.bis.saved.status(i16 5) + ret void +} + +@a = common dso_local local_unnamed_addr global i16 0, align 2 + +define msp430_intrcc void @bic() #0 { +; CHECK-LABEL: bic: +; CHECK: bic &a, @r1 + %1 = load i16, i16* @a, align 2 + %2 = call i16 @llvm.msp430.bic.saved.status(i16 %1) + ret void +} + +; Check that the intrinsic returns the value of the saved status register +; before the update. + +define dso_local msp430_intrcc void @foo() #0 { +; CHECK-LABEL: foo: +; CHECK: push r13 +; CHECK-NEXT: push r12 +; CHECK-NEXT: mov 4(r1), r12 +; CHECK-NEXT: mov r12, r13 +; CHECK-NEXT: bis #5, r13 +; CHECK-NEXT: mov r13, 4(r1) +; CHECK-NEXT: mov r12, &a + + %1 = tail call i16 @llvm.msp430.bis.saved.status(i16 5) + store i16 %1, i16* @a, align 2 + ret void +} + +declare i16 @llvm.msp430.bis.saved.status(i16) +declare i16 @llvm.msp430.bic.saved.status(i16) + +attributes #0 = {"interrupt"="1"} diff --git a/src/llvm/tools/clang/include/clang/Basic/BuiltinsMSP430.def b/src/llvm/tools/clang/include/clang/Basic/BuiltinsMSP430.def new file mode 100644 index 00000000000..d114a56aabc --- /dev/null +++ b/src/llvm/tools/clang/include/clang/Basic/BuiltinsMSP430.def @@ -0,0 +1,19 @@ +//===-- BuiltinsMips.def - Mips Builtin function database --------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the MIPS-specific builtin function database. Users of +// this file must define the BUILTIN macro to make use of this information. +// +//===----------------------------------------------------------------------===// + +// The format of this database matches clang/Basic/Builtins.def. + +// Add/subtract with optional saturation +BUILTIN(__bic_SR_register_on_exit, "UsUs", "") +BUILTIN(__bis_SR_register_on_exit, "UsUs", "") diff --git a/src/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td b/src/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td index b71f65d146c..e4b309a8213 100644 --- a/src/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/src/llvm/tools/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8309,6 +8309,8 @@ def err_hexagon_builtin_requires_hvx : Error< "builtin requires HVX">; def err_hexagon_builtin_unsupported_hvx : Error< "builtin is not supported on this version of HVX">; +def err_msp430_builtin_not_isr_caller : Error< + "builtin is only available within interrupt routines">; def err_builtin_target_unsupported : Error< "builtin is not supported on this target">; diff --git a/src/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h b/src/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h index ab4b1c43f7c..acc12773a8a 100644 --- a/src/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h +++ b/src/llvm/tools/clang/include/clang/Basic/TargetBuiltins.h @@ -160,6 +160,16 @@ namespace clang { }; } + /// MSP430 builtins + namespace MSP430 { + enum { + LastTIBuiltin = clang::Builtin::FirstTSBuiltin-1, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/BuiltinsMSP430.def" + LastTSBuiltin + }; + } + /// XCore builtins namespace XCore { enum { diff --git a/src/llvm/tools/clang/include/clang/Sema/Sema.h b/src/llvm/tools/clang/include/clang/Sema/Sema.h index e5b7465820a..2fe8fde998d 100644 --- a/src/llvm/tools/clang/include/clang/Sema/Sema.h +++ b/src/llvm/tools/clang/include/clang/Sema/Sema.h @@ -10514,6 +10514,7 @@ class Sema { bool CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, CallExpr *TheCall); bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + bool CheckMSP430BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call); diff --git a/src/llvm/tools/clang/lib/Basic/Targets/MSP430.cpp b/src/llvm/tools/clang/lib/Basic/Targets/MSP430.cpp index 86f85a398f1..14c91334b95 100644 --- a/src/llvm/tools/clang/lib/Basic/Targets/MSP430.cpp +++ b/src/llvm/tools/clang/lib/Basic/Targets/MSP430.cpp @@ -13,6 +13,7 @@ #include "MSP430.h" #include "clang/Basic/MacroBuilder.h" +#include "clang/Basic/TargetBuiltins.h" using namespace clang; using namespace clang::targets; @@ -22,6 +23,17 @@ const char *const MSP430TargetInfo::GCCRegNames[] = { "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }; +const Builtin::Info MSP430TargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + {#ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr}, +#include "clang/Basic/BuiltinsMSP430.def" +}; + +ArrayRef MSP430TargetInfo::getTargetBuiltins() const { + return llvm::makeArrayRef( + BuiltinInfo, clang::MSP430::LastTSBuiltin - Builtin::FirstTSBuiltin); +} + ArrayRef MSP430TargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } diff --git a/src/llvm/tools/clang/lib/Basic/Targets/MSP430.h b/src/llvm/tools/clang/lib/Basic/Targets/MSP430.h index 4ee54a371ac..b10c71f0ac1 100644 --- a/src/llvm/tools/clang/lib/Basic/Targets/MSP430.h +++ b/src/llvm/tools/clang/lib/Basic/Targets/MSP430.h @@ -24,6 +24,7 @@ namespace targets { class LLVM_LIBRARY_VISIBILITY MSP430TargetInfo : public TargetInfo { static const char *const GCCRegNames[]; + static const Builtin::Info BuiltinInfo[]; public: MSP430TargetInfo(const llvm::Triple &Triple, const TargetOptions &) @@ -48,10 +49,7 @@ class LLVM_LIBRARY_VISIBILITY MSP430TargetInfo : public TargetInfo { void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; - ArrayRef getTargetBuiltins() const override { - // FIXME: Implement. - return None; - } + ArrayRef getTargetBuiltins() const override; bool allowsLargerPreferedTypeAlignment() const override { return false; } diff --git a/src/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/src/llvm/tools/clang/lib/Sema/SemaChecking.cpp index 8dc1fdb7698..62abbd21bcb 100644 --- a/src/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/src/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -1475,6 +1475,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (CheckPPCBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; + case llvm::Triple::msp430: + if (CheckMSP430BuiltinFunctionCall(BuiltinID, TheCall)) + return ExprError(); + break; default: break; } @@ -3919,6 +3923,23 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return SemaBuiltinConstantArgRange(TheCall, i, l, u, /*RangeIsError*/ false); } +bool Sema::CheckMSP430BuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + switch (BuiltinID) { + default: + return false; + case MSP430::BI__bic_SR_register_on_exit: + case MSP430::BI__bis_SR_register_on_exit: + auto *FD = cast(CurContext); + // These builtins can only be used inside interrupt handlers. + if (!FD->hasAttr()) + return + Diag(TheCall->getBeginLoc(), diag::err_msp430_builtin_not_isr_caller) + << TheCall->getSourceRange(); + } + return false; +} + /// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo /// parameter with the FormatAttr's correct format_idx and firstDataArg. /// Returns true when the format fits the function and the FormatStringInfo has diff --git a/src/llvm/tools/clang/test/CodeGen/builtins-msp430.c b/src/llvm/tools/clang/test/CodeGen/builtins-msp430.c new file mode 100644 index 00000000000..71ee33808ff --- /dev/null +++ b/src/llvm/tools/clang/test/CodeGen/builtins-msp430.c @@ -0,0 +1,11 @@ +// REQUIRES: msp430-registered-target +// RUN: %clang_cc1 -triple msp430-elf -emit-llvm -o - %s | FileCheck %s + +__attribute__((interrupt(1))) void foo(void) { +// CHECK: call i16 @llvm.msp430.bic.saved.status(i16 1) + __bic_SR_register_on_exit(1); + +// CHECK: call i16 @llvm.msp430.bis.saved.status(i16 1) + __bis_SR_register_on_exit(1); +} + diff --git a/src/llvm/tools/clang/test/Sema/builtins-msp430.c b/src/llvm/tools/clang/test/Sema/builtins-msp430.c new file mode 100644 index 00000000000..c96abac69d3 --- /dev/null +++ b/src/llvm/tools/clang/test/Sema/builtins-msp430.c @@ -0,0 +1,14 @@ +// REQUIRES: msp430-registered-target +// RUN: %clang_cc1 %s -triple msp430-elf -fsyntax-only -verify + +void f(void) { + __bic_SR_register_on_exit(1); // expected-error {{builtin is only available within interrupt routines}} + __bis_SR_register_on_exit(1); // expected-error {{builtin is only available within interrupt routines}} +} + +__attribute__((interrupt(1))) +void ISR(void) { + __bic_SR_register_on_exit(1); + __bis_SR_register_on_exit(1); +} +