diff --git a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h --- a/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -235,7 +235,7 @@ bool translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID, MachineIRBuilder &MIRBuilder); - bool translateInlineAsm(const CallInst &CI, MachineIRBuilder &MIRBuilder); + bool translateInlineAsm(const CallBase &CB, MachineIRBuilder &MIRBuilder); /// Returns true if the value should be split into multiple LLTs. /// If \p Offsets is given then the split type's offsets will be stored in it. diff --git a/llvm/include/llvm/CodeGen/GlobalISel/InlineAsmLowering.h b/llvm/include/llvm/CodeGen/GlobalISel/InlineAsmLowering.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/CodeGen/GlobalISel/InlineAsmLowering.h @@ -0,0 +1,46 @@ +//===- llvm/CodeGen/GlobalISel/InlineAsmLowering.h --------------*- 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file describes how to lower LLVM inline asm to machine code INLINEASM. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_GLOBALISEL_INLINEASMLOWERING_H +#define LLVM_CODEGEN_GLOBALISEL_INLINEASMLOWERING_H + +namespace llvm { +class CallBase; +class MachineIRBuilder; +class TargetLowering; + +class InlineAsmLowering { + const TargetLowering *TLI; + + virtual void anchor(); + +public: + bool lowerInlineAsm(MachineIRBuilder &MIRBuilder, const CallBase &CB) const; + +protected: + /// Getter for generic TargetLowering class. + const TargetLowering *getTLI() const { return TLI; } + + /// Getter for target specific TargetLowering class. + template const XXXTargetLowering *getTLI() const { + return static_cast(TLI); + } + +public: + InlineAsmLowering(const TargetLowering *TLI) : TLI(TLI) {} + virtual ~InlineAsmLowering() = default; +}; + +} // end namespace llvm + +#endif // LLVM_CODEGEN_GLOBALISEL_INLINEASMLOWERING_H diff --git a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h --- a/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h +++ b/llvm/include/llvm/CodeGen/TargetSubtargetInfo.h @@ -29,6 +29,7 @@ namespace llvm { class CallLowering; +class InlineAsmLowering; class InstrItineraryData; struct InstrStage; class InstructionSelector; @@ -102,6 +103,10 @@ } virtual const CallLowering *getCallLowering() const { return nullptr; } + virtual const InlineAsmLowering *getInlineAsmLowering() const { + return nullptr; + } + // FIXME: This lets targets specialize the selector by subtarget (which lets // us do things like a dedicated avx512 selector). However, we might want // to also specialize selectors by MachineFunction, which would let us be diff --git a/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt b/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt --- a/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt +++ b/llvm/lib/CodeGen/GlobalISel/CMakeLists.txt @@ -8,6 +8,7 @@ CombinerHelper.cpp GISelChangeObserver.cpp IRTranslator.cpp + InlineAsmLowering.cpp InstructionSelect.cpp InstructionSelector.cpp LegalityPredicates.cpp diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -23,6 +23,7 @@ #include "llvm/CodeGen/FunctionLoweringInfo.h" #include "llvm/CodeGen/GlobalISel/CallLowering.h" #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" +#include "llvm/CodeGen/GlobalISel/InlineAsmLowering.h" #include "llvm/CodeGen/LowLevelType.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFrameInfo.h" @@ -1565,37 +1566,18 @@ return false; } -bool IRTranslator::translateInlineAsm(const CallInst &CI, +bool IRTranslator::translateInlineAsm(const CallBase &CB, MachineIRBuilder &MIRBuilder) { - const InlineAsm &IA = cast(*CI.getCalledValue()); - StringRef ConstraintStr = IA.getConstraintString(); - - bool HasOnlyMemoryClobber = false; - if (!ConstraintStr.empty()) { - // Until we have full inline assembly support, we just try to handle the - // very simple case of just "~{memory}" to avoid falling back so often. - if (ConstraintStr != "~{memory}") - return false; - HasOnlyMemoryClobber = true; - } - - unsigned ExtraInfo = 0; - if (IA.hasSideEffects()) - ExtraInfo |= InlineAsm::Extra_HasSideEffects; - if (IA.getDialect() == InlineAsm::AD_Intel) - ExtraInfo |= InlineAsm::Extra_AsmDialect; - // HACK: special casing for ~memory. - if (HasOnlyMemoryClobber) - ExtraInfo |= (InlineAsm::Extra_MayLoad | InlineAsm::Extra_MayStore); + const InlineAsmLowering *ALI = MF->getSubtarget().getInlineAsmLowering(); - auto Inst = MIRBuilder.buildInstr(TargetOpcode::INLINEASM) - .addExternalSymbol(IA.getAsmString().c_str()) - .addImm(ExtraInfo); - if (const MDNode *SrcLoc = CI.getMetadata("srcloc")) - Inst.addMetadata(SrcLoc); + if (!ALI) { + LLVM_DEBUG( + dbgs() << "Inline asm lowering is not supported for this target yet\n"); + return false; + } - return true; + return ALI->lowerInlineAsm(MIRBuilder, CB); } bool IRTranslator::translateCallBase(const CallBase &CB, diff --git a/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/GlobalISel/InlineAsmLowering.cpp @@ -0,0 +1,64 @@ +//===-- lib/CodeGen/GlobalISel/InlineAsmLowering.cpp ----------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file implements the lowering from LLVM IR inline asm to MIR INLINEASM +/// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/GlobalISel/InlineAsmLowering.h" +#include "llvm/CodeGen/Analysis.h" +#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" +#include "llvm/CodeGen/GlobalISel/Utils.h" +#include "llvm/CodeGen/MachineOperand.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetLowering.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" + +#define DEBUG_TYPE "inline-asm-lowering" + +using namespace llvm; + +void InlineAsmLowering::anchor() {} + +bool InlineAsmLowering::lowerInlineAsm(MachineIRBuilder &MIRBuilder, + const CallBase &Call) const { + + const InlineAsm *IA = cast(Call.getCalledValue()); + StringRef ConstraintStr = IA->getConstraintString(); + + bool HasOnlyMemoryClobber = false; + if (!ConstraintStr.empty()) { + // Until we have full inline assembly support, we just try to handle the + // very simple case of just "~{memory}" to avoid falling back so often. + if (ConstraintStr != "~{memory}") + return false; + HasOnlyMemoryClobber = true; + } + + unsigned ExtraInfo = 0; + if (IA->hasSideEffects()) + ExtraInfo |= InlineAsm::Extra_HasSideEffects; + if (IA->getDialect() == InlineAsm::AD_Intel) + ExtraInfo |= InlineAsm::Extra_AsmDialect; + + // HACK: special casing for ~memory. + if (HasOnlyMemoryClobber) + ExtraInfo |= (InlineAsm::Extra_MayLoad | InlineAsm::Extra_MayStore); + + auto Inst = MIRBuilder.buildInstr(TargetOpcode::INLINEASM) + .addExternalSymbol(IA->getAsmString().c_str()) + .addImm(ExtraInfo); + if (const MDNode *SrcLoc = Call.getMetadata("srcloc")) + Inst.addMetadata(SrcLoc); + + return true; +} diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h --- a/llvm/lib/Target/AArch64/AArch64Subtarget.h +++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h @@ -19,6 +19,7 @@ #include "AArch64RegisterInfo.h" #include "AArch64SelectionDAGInfo.h" #include "llvm/CodeGen/GlobalISel/CallLowering.h" +#include "llvm/CodeGen/GlobalISel/InlineAsmLowering.h" #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" @@ -233,6 +234,7 @@ /// GlobalISel related APIs. std::unique_ptr CallLoweringInfo; + std::unique_ptr InlineAsmLoweringInfo; std::unique_ptr InstSelector; std::unique_ptr Legalizer; std::unique_ptr RegBankInfo; @@ -268,6 +270,7 @@ return &getInstrInfo()->getRegisterInfo(); } const CallLowering *getCallLowering() const override; + const InlineAsmLowering *getInlineAsmLowering() const override; InstructionSelector *getInstructionSelector() const override; const LegalizerInfo *getLegalizerInfo() const override; const RegisterBankInfo *getRegBankInfo() const override; diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp --- a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp +++ b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp @@ -182,6 +182,7 @@ ReserveXRegister.set(18); CallLoweringInfo.reset(new AArch64CallLowering(*getTargetLowering())); + InlineAsmLoweringInfo.reset(new InlineAsmLowering(getTargetLowering())); Legalizer.reset(new AArch64LegalizerInfo(*this)); auto *RBI = new AArch64RegisterBankInfo(*getRegisterInfo()); @@ -199,6 +200,10 @@ return CallLoweringInfo.get(); } +const InlineAsmLowering *AArch64Subtarget::getInlineAsmLowering() const { + return InlineAsmLoweringInfo.get(); +} + InstructionSelector *AArch64Subtarget::getInstructionSelector() const { return InstSelector.get(); }