2017-06-27 06:44:03 +08:00
|
|
|
|
//===- llvm/CodeGen/GlobalISel/IRTranslator.cpp - IRTranslator ---*- C++ -*-==//
|
2016-01-21 04:58:56 +08:00
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
|
// 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
|
2016-01-21 04:58:56 +08:00
|
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
/// \file
|
|
|
|
|
/// This file implements the IRTranslator class.
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
|
|
#include "llvm/CodeGen/GlobalISel/IRTranslator.h"
|
2018-08-01 10:17:42 +08:00
|
|
|
|
#include "llvm/ADT/PostOrderIterator.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2017-02-24 07:57:28 +08:00
|
|
|
|
#include "llvm/ADT/ScopeExit.h"
|
2017-01-18 06:13:50 +08:00
|
|
|
|
#include "llvm/ADT/SmallSet.h"
|
2016-02-12 03:59:41 +08:00
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2017-10-10 07:19:02 +08:00
|
|
|
|
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
|
2019-01-29 03:22:29 +08:00
|
|
|
|
#include "llvm/Analysis/ValueTracking.h"
|
2016-11-10 06:39:54 +08:00
|
|
|
|
#include "llvm/CodeGen/Analysis.h"
|
2017-06-06 19:49:48 +08:00
|
|
|
|
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
|
2019-01-16 08:40:37 +08:00
|
|
|
|
#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#include "llvm/CodeGen/LowLevelType.h"
|
|
|
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
2016-07-23 00:59:52 +08:00
|
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
2017-06-06 19:49:48 +08:00
|
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
|
|
|
#include "llvm/CodeGen/MachineMemOperand.h"
|
|
|
|
|
#include "llvm/CodeGen/MachineOperand.h"
|
2016-02-12 01:51:31 +08:00
|
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
2018-07-13 08:08:38 +08:00
|
|
|
|
#include "llvm/CodeGen/StackProtector.h"
|
2017-11-17 09:07:10 +08:00
|
|
|
|
#include "llvm/CodeGen/TargetFrameLowering.h"
|
|
|
|
|
#include "llvm/CodeGen/TargetLowering.h"
|
2016-08-27 07:49:05 +08:00
|
|
|
|
#include "llvm/CodeGen/TargetPassConfig.h"
|
2017-11-17 09:07:10 +08:00
|
|
|
|
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
|
|
|
|
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#include "llvm/IR/BasicBlock.h"
|
2018-08-01 10:17:42 +08:00
|
|
|
|
#include "llvm/IR/CFG.h"
|
2016-02-12 01:51:31 +08:00
|
|
|
|
#include "llvm/IR/Constant.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#include "llvm/IR/Constants.h"
|
|
|
|
|
#include "llvm/IR/DataLayout.h"
|
2017-01-27 07:39:14 +08:00
|
|
|
|
#include "llvm/IR/DebugInfo.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
2016-02-11 06:59:27 +08:00
|
|
|
|
#include "llvm/IR/Function.h"
|
2016-09-12 19:20:22 +08:00
|
|
|
|
#include "llvm/IR/GetElementPtrTypeIterator.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#include "llvm/IR/InlineAsm.h"
|
|
|
|
|
#include "llvm/IR/InstrTypes.h"
|
|
|
|
|
#include "llvm/IR/Instructions.h"
|
2016-07-30 06:32:36 +08:00
|
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#include "llvm/IR/Intrinsics.h"
|
|
|
|
|
#include "llvm/IR/LLVMContext.h"
|
|
|
|
|
#include "llvm/IR/Metadata.h"
|
2016-02-12 01:51:31 +08:00
|
|
|
|
#include "llvm/IR/Type.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#include "llvm/IR/User.h"
|
2016-02-12 01:51:31 +08:00
|
|
|
|
#include "llvm/IR/Value.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#include "llvm/MC/MCContext.h"
|
|
|
|
|
#include "llvm/Pass.h"
|
|
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
|
#include "llvm/Support/CodeGen.h"
|
|
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
|
#include "llvm/Support/LowLevelTypeImpl.h"
|
|
|
|
|
#include "llvm/Support/MathExtras.h"
|
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2016-07-30 06:32:36 +08:00
|
|
|
|
#include "llvm/Target/TargetIntrinsicInfo.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <iterator>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <utility>
|
|
|
|
|
#include <vector>
|
2016-02-11 06:59:27 +08:00
|
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "irtranslator"
|
|
|
|
|
|
2016-01-21 04:58:56 +08:00
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
2019-01-16 08:40:37 +08:00
|
|
|
|
static cl::opt<bool>
|
|
|
|
|
EnableCSEInIRTranslator("enable-cse-in-irtranslator",
|
|
|
|
|
cl::desc("Should enable CSE in irtranslator"),
|
|
|
|
|
cl::Optional, cl::init(false));
|
2016-01-21 04:58:56 +08:00
|
|
|
|
char IRTranslator::ID = 0;
|
2017-06-27 06:44:03 +08:00
|
|
|
|
|
2016-08-27 07:49:05 +08:00
|
|
|
|
INITIALIZE_PASS_BEGIN(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI",
|
|
|
|
|
false, false)
|
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
|
2019-01-16 08:40:37 +08:00
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)
|
2016-08-27 07:49:05 +08:00
|
|
|
|
INITIALIZE_PASS_END(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI",
|
2016-07-26 11:29:18 +08:00
|
|
|
|
false, false)
|
2016-01-21 04:58:56 +08:00
|
|
|
|
|
2017-02-24 05:05:42 +08:00
|
|
|
|
static void reportTranslationError(MachineFunction &MF,
|
|
|
|
|
const TargetPassConfig &TPC,
|
|
|
|
|
OptimizationRemarkEmitter &ORE,
|
|
|
|
|
OptimizationRemarkMissed &R) {
|
|
|
|
|
MF.getProperties().set(MachineFunctionProperties::Property::FailedISel);
|
|
|
|
|
|
|
|
|
|
// Print the function name explicitly if we don't have a debug location (which
|
|
|
|
|
// makes the diagnostic less useful) or if we're going to emit a raw error.
|
|
|
|
|
if (!R.getLocation().isValid() || TPC.isGlobalISelAbortEnabled())
|
|
|
|
|
R << (" (in function: " + MF.getName() + ")").str();
|
|
|
|
|
|
|
|
|
|
if (TPC.isGlobalISelAbortEnabled())
|
|
|
|
|
report_fatal_error(R.getMsg());
|
|
|
|
|
else
|
|
|
|
|
ORE.emit(R);
|
2016-11-08 09:12:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-27 06:44:03 +08:00
|
|
|
|
IRTranslator::IRTranslator() : MachineFunctionPass(ID) {
|
2016-03-08 09:38:55 +08:00
|
|
|
|
initializeIRTranslatorPass(*PassRegistry::getPassRegistry());
|
2016-02-12 01:53:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
#ifndef NDEBUG
|
2019-01-13 02:36:22 +08:00
|
|
|
|
namespace {
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
/// Verify that every instruction created has the same DILocation as the
|
|
|
|
|
/// instruction being translated.
|
2019-01-16 08:40:37 +08:00
|
|
|
|
class DILocationVerifier : public GISelChangeObserver {
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
const Instruction *CurrInst = nullptr;
|
|
|
|
|
|
|
|
|
|
public:
|
2019-01-16 08:40:37 +08:00
|
|
|
|
DILocationVerifier() = default;
|
|
|
|
|
~DILocationVerifier() = default;
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
|
|
|
|
|
const Instruction *getCurrentInst() const { return CurrInst; }
|
|
|
|
|
void setCurrentInst(const Instruction *Inst) { CurrInst = Inst; }
|
|
|
|
|
|
2019-01-16 08:40:37 +08:00
|
|
|
|
void erasingInstr(MachineInstr &MI) override {}
|
|
|
|
|
void changingInstr(MachineInstr &MI) override {}
|
|
|
|
|
void changedInstr(MachineInstr &MI) override {}
|
|
|
|
|
|
|
|
|
|
void createdInstr(MachineInstr &MI) override {
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
assert(getCurrentInst() && "Inserted instruction without a current MI");
|
|
|
|
|
|
|
|
|
|
// Only print the check message if we're actually checking it.
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
LLVM_DEBUG(dbgs() << "Checking DILocation from " << *CurrInst
|
|
|
|
|
<< " was copied to " << MI);
|
|
|
|
|
#endif
|
|
|
|
|
assert(CurrInst->getDebugLoc() == MI.getDebugLoc() &&
|
|
|
|
|
"Line info was not transferred to all instructions");
|
|
|
|
|
}
|
|
|
|
|
};
|
2019-01-13 02:36:22 +08:00
|
|
|
|
} // namespace
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
#endif // ifndef NDEBUG
|
|
|
|
|
|
|
|
|
|
|
2016-08-27 07:49:05 +08:00
|
|
|
|
void IRTranslator::getAnalysisUsage(AnalysisUsage &AU) const {
|
2018-07-13 08:08:38 +08:00
|
|
|
|
AU.addRequired<StackProtector>();
|
2016-08-27 07:49:05 +08:00
|
|
|
|
AU.addRequired<TargetPassConfig>();
|
2019-01-16 08:40:37 +08:00
|
|
|
|
AU.addRequired<GISelCSEAnalysisWrapperPass>();
|
2018-07-13 08:08:38 +08:00
|
|
|
|
getSelectionDAGFallbackAnalysisUsage(AU);
|
2016-08-27 07:49:05 +08:00
|
|
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
static void computeValueLLTs(const DataLayout &DL, Type &Ty,
|
|
|
|
|
SmallVectorImpl<LLT> &ValueTys,
|
|
|
|
|
SmallVectorImpl<uint64_t> *Offsets = nullptr,
|
|
|
|
|
uint64_t StartingOffset = 0) {
|
|
|
|
|
// Given a struct type, recursively traverse the elements.
|
|
|
|
|
if (StructType *STy = dyn_cast<StructType>(&Ty)) {
|
|
|
|
|
const StructLayout *SL = DL.getStructLayout(STy);
|
|
|
|
|
for (unsigned I = 0, E = STy->getNumElements(); I != E; ++I)
|
|
|
|
|
computeValueLLTs(DL, *STy->getElementType(I), ValueTys, Offsets,
|
|
|
|
|
StartingOffset + SL->getElementOffset(I));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Given an array type, recursively traverse the elements.
|
|
|
|
|
if (ArrayType *ATy = dyn_cast<ArrayType>(&Ty)) {
|
|
|
|
|
Type *EltTy = ATy->getElementType();
|
|
|
|
|
uint64_t EltSize = DL.getTypeAllocSize(EltTy);
|
|
|
|
|
for (unsigned i = 0, e = ATy->getNumElements(); i != e; ++i)
|
|
|
|
|
computeValueLLTs(DL, *EltTy, ValueTys, Offsets,
|
|
|
|
|
StartingOffset + i * EltSize);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// Interpret void as zero return values.
|
|
|
|
|
if (Ty.isVoidTy())
|
|
|
|
|
return;
|
|
|
|
|
// Base case: we can get an LLT for this LLVM IR type.
|
|
|
|
|
ValueTys.push_back(getLLTForType(Ty, DL));
|
|
|
|
|
if (Offsets != nullptr)
|
|
|
|
|
Offsets->push_back(StartingOffset * 8);
|
|
|
|
|
}
|
2017-01-26 04:58:22 +08:00
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
IRTranslator::ValueToVRegInfo::VRegListT &
|
|
|
|
|
IRTranslator::allocateVRegs(const Value &Val) {
|
|
|
|
|
assert(!VMap.contains(Val) && "Value already allocated in VMap");
|
|
|
|
|
auto *Regs = VMap.getVRegs(Val);
|
|
|
|
|
auto *Offsets = VMap.getOffsets(Val);
|
|
|
|
|
SmallVector<LLT, 4> SplitTys;
|
|
|
|
|
computeValueLLTs(*DL, *Val.getType(), SplitTys,
|
|
|
|
|
Offsets->empty() ? Offsets : nullptr);
|
|
|
|
|
for (unsigned i = 0; i < SplitTys.size(); ++i)
|
|
|
|
|
Regs->push_back(0);
|
|
|
|
|
return *Regs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ArrayRef<unsigned> IRTranslator::getOrCreateVRegs(const Value &Val) {
|
|
|
|
|
auto VRegsIt = VMap.findVRegs(Val);
|
|
|
|
|
if (VRegsIt != VMap.vregs_end())
|
|
|
|
|
return *VRegsIt->second;
|
|
|
|
|
|
|
|
|
|
if (Val.getType()->isVoidTy())
|
|
|
|
|
return *VMap.getVRegs(Val);
|
|
|
|
|
|
|
|
|
|
// Create entry for this type.
|
|
|
|
|
auto *VRegs = VMap.getVRegs(Val);
|
|
|
|
|
auto *Offsets = VMap.getOffsets(Val);
|
2017-01-26 04:58:22 +08:00
|
|
|
|
|
|
|
|
|
assert(Val.getType()->isSized() &&
|
|
|
|
|
"Don't know how to create an empty vreg");
|
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
SmallVector<LLT, 4> SplitTys;
|
|
|
|
|
computeValueLLTs(*DL, *Val.getType(), SplitTys,
|
|
|
|
|
Offsets->empty() ? Offsets : nullptr);
|
|
|
|
|
|
|
|
|
|
if (!isa<Constant>(Val)) {
|
|
|
|
|
for (auto Ty : SplitTys)
|
|
|
|
|
VRegs->push_back(MRI->createGenericVirtualRegister(Ty));
|
|
|
|
|
return *VRegs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Val.getType()->isAggregateType()) {
|
|
|
|
|
// UndefValue, ConstantAggregateZero
|
|
|
|
|
auto &C = cast<Constant>(Val);
|
|
|
|
|
unsigned Idx = 0;
|
|
|
|
|
while (auto Elt = C.getAggregateElement(Idx++)) {
|
|
|
|
|
auto EltRegs = getOrCreateVRegs(*Elt);
|
2018-11-17 09:44:25 +08:00
|
|
|
|
llvm::copy(EltRegs, std::back_inserter(*VRegs));
|
2018-05-16 18:32:02 +08:00
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
assert(SplitTys.size() == 1 && "unexpectedly split LLT");
|
|
|
|
|
VRegs->push_back(MRI->createGenericVirtualRegister(SplitTys[0]));
|
|
|
|
|
bool Success = translate(cast<Constant>(Val), VRegs->front());
|
2017-01-26 04:58:22 +08:00
|
|
|
|
if (!Success) {
|
2017-02-24 05:05:42 +08:00
|
|
|
|
OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",
|
2017-12-16 06:22:58 +08:00
|
|
|
|
MF->getFunction().getSubprogram(),
|
|
|
|
|
&MF->getFunction().getEntryBlock());
|
2017-02-24 05:05:42 +08:00
|
|
|
|
R << "unable to translate constant: " << ore::NV("Type", Val.getType());
|
|
|
|
|
reportTranslationError(*MF, *TPC, *ORE, R);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
return *VRegs;
|
2016-08-10 05:28:04 +08:00
|
|
|
|
}
|
2016-02-12 01:51:31 +08:00
|
|
|
|
}
|
2017-01-21 07:25:17 +08:00
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
return *VRegs;
|
2016-02-12 01:51:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-01 02:30:59 +08:00
|
|
|
|
int IRTranslator::getOrCreateFrameIndex(const AllocaInst &AI) {
|
|
|
|
|
if (FrameIndices.find(&AI) != FrameIndices.end())
|
|
|
|
|
return FrameIndices[&AI];
|
|
|
|
|
|
|
|
|
|
unsigned ElementSize = DL->getTypeStoreSize(AI.getAllocatedType());
|
|
|
|
|
unsigned Size =
|
|
|
|
|
ElementSize * cast<ConstantInt>(AI.getArraySize())->getZExtValue();
|
|
|
|
|
|
|
|
|
|
// Always allocate at least one byte.
|
|
|
|
|
Size = std::max(Size, 1u);
|
|
|
|
|
|
|
|
|
|
unsigned Alignment = AI.getAlignment();
|
|
|
|
|
if (!Alignment)
|
|
|
|
|
Alignment = DL->getABITypeAlignment(AI.getAllocatedType());
|
|
|
|
|
|
|
|
|
|
int &FI = FrameIndices[&AI];
|
2016-12-08 05:17:47 +08:00
|
|
|
|
FI = MF->getFrameInfo().CreateStackObject(Size, Alignment, false, &AI);
|
2016-11-01 02:30:59 +08:00
|
|
|
|
return FI;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-27 04:23:26 +08:00
|
|
|
|
unsigned IRTranslator::getMemOpAlignment(const Instruction &I) {
|
|
|
|
|
unsigned Alignment = 0;
|
|
|
|
|
Type *ValTy = nullptr;
|
|
|
|
|
if (const StoreInst *SI = dyn_cast<StoreInst>(&I)) {
|
|
|
|
|
Alignment = SI->getAlignment();
|
|
|
|
|
ValTy = SI->getValueOperand()->getType();
|
|
|
|
|
} else if (const LoadInst *LI = dyn_cast<LoadInst>(&I)) {
|
|
|
|
|
Alignment = LI->getAlignment();
|
|
|
|
|
ValTy = LI->getType();
|
[globalisel][irtranslator] Add support for atomicrmw and (strong) cmpxchg
Summary:
This patch adds support for the atomicrmw instructions and the strong
cmpxchg instruction to the IRTranslator.
I've left out weak cmpxchg because LangRef.rst isn't entirely clear on what
difference it makes to the backend. As far as I can tell from the code, it
only matters to AtomicExpandPass which is run at the LLVM-IR level.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar, volkan, javed.absar
Reviewed By: qcolombet
Subscribers: kristof.beyls, javed.absar, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D40092
llvm-svn: 336589
2018-07-10 03:33:40 +08:00
|
|
|
|
} else if (const AtomicCmpXchgInst *AI = dyn_cast<AtomicCmpXchgInst>(&I)) {
|
|
|
|
|
// TODO(PR27168): This instruction has no alignment attribute, but unlike
|
|
|
|
|
// the default alignment for load/store, the default here is to assume
|
|
|
|
|
// it has NATURAL alignment, not DataLayout-specified alignment.
|
|
|
|
|
const DataLayout &DL = AI->getModule()->getDataLayout();
|
|
|
|
|
Alignment = DL.getTypeStoreSize(AI->getCompareOperand()->getType());
|
|
|
|
|
ValTy = AI->getCompareOperand()->getType();
|
|
|
|
|
} else if (const AtomicRMWInst *AI = dyn_cast<AtomicRMWInst>(&I)) {
|
|
|
|
|
// TODO(PR27168): This instruction has no alignment attribute, but unlike
|
|
|
|
|
// the default alignment for load/store, the default here is to assume
|
|
|
|
|
// it has NATURAL alignment, not DataLayout-specified alignment.
|
|
|
|
|
const DataLayout &DL = AI->getModule()->getDataLayout();
|
|
|
|
|
Alignment = DL.getTypeStoreSize(AI->getValOperand()->getType());
|
|
|
|
|
ValTy = AI->getType();
|
2017-02-24 05:05:42 +08:00
|
|
|
|
} else {
|
|
|
|
|
OptimizationRemarkMissed R("gisel-irtranslator", "", &I);
|
|
|
|
|
R << "unable to translate memop: " << ore::NV("Opcode", &I);
|
|
|
|
|
reportTranslationError(*MF, *TPC, *ORE, R);
|
2016-08-27 07:49:05 +08:00
|
|
|
|
return 1;
|
2017-02-24 05:05:42 +08:00
|
|
|
|
}
|
2016-07-27 04:23:26 +08:00
|
|
|
|
|
|
|
|
|
return Alignment ? Alignment : DL->getABITypeAlignment(ValTy);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-16 02:22:33 +08:00
|
|
|
|
MachineBasicBlock &IRTranslator::getMBB(const BasicBlock &BB) {
|
2016-03-12 01:27:43 +08:00
|
|
|
|
MachineBasicBlock *&MBB = BBToMBB[&BB];
|
2017-03-16 02:22:33 +08:00
|
|
|
|
assert(MBB && "BasicBlock was not encountered before");
|
2016-02-12 01:51:31 +08:00
|
|
|
|
return *MBB;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-18 06:13:50 +08:00
|
|
|
|
void IRTranslator::addMachineCFGPred(CFGEdge Edge, MachineBasicBlock *NewPred) {
|
|
|
|
|
assert(NewPred && "new predecessor must be a real MachineBasicBlock");
|
|
|
|
|
MachinePreds[Edge].push_back(NewPred);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateBinaryOp(unsigned Opcode, const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-07-30 02:11:21 +08:00
|
|
|
|
// FIXME: handle signed/unsigned wrapping flags.
|
|
|
|
|
|
2016-02-11 06:59:27 +08:00
|
|
|
|
// Get or create a virtual register for each value.
|
|
|
|
|
// Unless the value is a Constant => loadimm cst?
|
|
|
|
|
// or inline constant each time?
|
|
|
|
|
// Creation of a virtual register needs to have a size.
|
2016-08-11 07:02:41 +08:00
|
|
|
|
unsigned Op0 = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
|
unsigned Op1 = getOrCreateVReg(*U.getOperand(1));
|
|
|
|
|
unsigned Res = getOrCreateVReg(U);
|
2019-02-07 03:57:06 +08:00
|
|
|
|
uint16_t Flags = 0;
|
2018-09-20 02:52:08 +08:00
|
|
|
|
if (isa<Instruction>(U)) {
|
|
|
|
|
const Instruction &I = cast<Instruction>(U);
|
2019-02-07 03:57:06 +08:00
|
|
|
|
Flags = MachineInstr::copyFlagsFromInstruction(I);
|
2018-09-20 02:52:08 +08:00
|
|
|
|
}
|
2019-02-07 03:57:06 +08:00
|
|
|
|
|
|
|
|
|
MIRBuilder.buildInstr(Opcode, {Res}, {Op0, Op1}, Flags);
|
2016-02-12 01:51:31 +08:00
|
|
|
|
return true;
|
2016-01-21 04:58:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-08 02:03:28 +08:00
|
|
|
|
bool IRTranslator::translateFSub(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
// -0.0 - X --> G_FNEG
|
|
|
|
|
if (isa<Constant>(U.getOperand(0)) &&
|
|
|
|
|
U.getOperand(0) == ConstantFP::getZeroValueForNegation(U.getType())) {
|
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FNEG)
|
|
|
|
|
.addDef(getOrCreateVReg(U))
|
|
|
|
|
.addUse(getOrCreateVReg(*U.getOperand(1)));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return translateBinaryOp(TargetOpcode::G_FSUB, U, MIRBuilder);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-14 02:15:47 +08:00
|
|
|
|
bool IRTranslator::translateFNeg(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FNEG)
|
|
|
|
|
.addDef(getOrCreateVReg(U))
|
2019-01-27 07:47:09 +08:00
|
|
|
|
.addUse(getOrCreateVReg(*U.getOperand(0)));
|
2018-11-14 02:15:47 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateCompare(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-08-20 04:48:16 +08:00
|
|
|
|
const CmpInst *CI = dyn_cast<CmpInst>(&U);
|
|
|
|
|
unsigned Op0 = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
|
unsigned Op1 = getOrCreateVReg(*U.getOperand(1));
|
|
|
|
|
unsigned Res = getOrCreateVReg(U);
|
|
|
|
|
CmpInst::Predicate Pred =
|
|
|
|
|
CI ? CI->getPredicate() : static_cast<CmpInst::Predicate>(
|
|
|
|
|
cast<ConstantExpr>(U).getPredicate());
|
|
|
|
|
if (CmpInst::isIntPredicate(Pred))
|
2016-09-09 19:46:34 +08:00
|
|
|
|
MIRBuilder.buildICmp(Pred, Res, Op0, Op1);
|
2017-03-09 02:49:54 +08:00
|
|
|
|
else if (Pred == CmpInst::FCMP_FALSE)
|
2017-03-16 03:21:11 +08:00
|
|
|
|
MIRBuilder.buildCopy(
|
|
|
|
|
Res, getOrCreateVReg(*Constant::getNullValue(CI->getType())));
|
|
|
|
|
else if (Pred == CmpInst::FCMP_TRUE)
|
|
|
|
|
MIRBuilder.buildCopy(
|
|
|
|
|
Res, getOrCreateVReg(*Constant::getAllOnesValue(CI->getType())));
|
2018-12-19 01:54:52 +08:00
|
|
|
|
else {
|
2019-02-07 03:57:06 +08:00
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FCMP, {Res}, {Pred, Op0, Op1},
|
|
|
|
|
MachineInstr::copyFlagsFromInstruction(*CI));
|
2018-12-19 01:54:52 +08:00
|
|
|
|
}
|
2016-08-20 04:48:16 +08:00
|
|
|
|
|
2016-08-18 04:25:25 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateRet(const User &U, MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
|
const ReturnInst &RI = cast<ReturnInst>(U);
|
2016-07-30 02:11:21 +08:00
|
|
|
|
const Value *Ret = RI.getReturnValue();
|
2017-12-01 04:06:02 +08:00
|
|
|
|
if (Ret && DL->getTypeStoreSize(Ret->getType()) == 0)
|
|
|
|
|
Ret = nullptr;
|
2018-08-02 16:33:31 +08:00
|
|
|
|
|
|
|
|
|
ArrayRef<unsigned> VRegs;
|
|
|
|
|
if (Ret)
|
|
|
|
|
VRegs = getOrCreateVRegs(*Ret);
|
|
|
|
|
|
2016-02-12 02:53:28 +08:00
|
|
|
|
// The target may mess up with the insertion point, but
|
|
|
|
|
// this is not important as a return is the last instruction
|
|
|
|
|
// of the block anyway.
|
2018-05-16 18:32:02 +08:00
|
|
|
|
|
2018-08-02 16:33:31 +08:00
|
|
|
|
return CLI->lowerReturn(MIRBuilder, Ret, VRegs);
|
2016-02-12 02:53:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateBr(const User &U, MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
|
const BranchInst &BrInst = cast<BranchInst>(U);
|
2016-07-30 01:58:00 +08:00
|
|
|
|
unsigned Succ = 0;
|
|
|
|
|
if (!BrInst.isUnconditional()) {
|
|
|
|
|
// We want a G_BRCOND to the true BB followed by an unconditional branch.
|
|
|
|
|
unsigned Tst = getOrCreateVReg(*BrInst.getCondition());
|
|
|
|
|
const BasicBlock &TrueTgt = *cast<BasicBlock>(BrInst.getSuccessor(Succ++));
|
2017-03-16 02:22:33 +08:00
|
|
|
|
MachineBasicBlock &TrueBB = getMBB(TrueTgt);
|
2016-09-09 19:46:34 +08:00
|
|
|
|
MIRBuilder.buildBrCond(Tst, TrueBB);
|
2016-03-12 01:28:03 +08:00
|
|
|
|
}
|
2016-07-30 01:58:00 +08:00
|
|
|
|
|
|
|
|
|
const BasicBlock &BrTgt = *cast<BasicBlock>(BrInst.getSuccessor(Succ));
|
2017-03-16 02:22:33 +08:00
|
|
|
|
MachineBasicBlock &TgtBB = getMBB(BrTgt);
|
2017-03-22 07:42:50 +08:00
|
|
|
|
MachineBasicBlock &CurBB = MIRBuilder.getMBB();
|
|
|
|
|
|
|
|
|
|
// If the unconditional target is the layout successor, fallthrough.
|
|
|
|
|
if (!CurBB.isLayoutSuccessor(&TgtBB))
|
|
|
|
|
MIRBuilder.buildBr(TgtBB);
|
2016-07-30 01:58:00 +08:00
|
|
|
|
|
2016-03-12 01:28:03 +08:00
|
|
|
|
// Link successors.
|
2018-08-26 16:41:15 +08:00
|
|
|
|
for (const BasicBlock *Succ : successors(&BrInst))
|
2017-03-16 02:22:33 +08:00
|
|
|
|
CurBB.addSuccessor(&getMBB(*Succ));
|
2016-03-12 01:28:03 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-05 19:28:51 +08:00
|
|
|
|
bool IRTranslator::translateSwitch(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
// For now, just translate as a chain of conditional branches.
|
|
|
|
|
// FIXME: could we share most of the logic/code in
|
|
|
|
|
// SelectionDAGBuilder::visitSwitch between SelectionDAG and GlobalISel?
|
|
|
|
|
// At first sight, it seems most of the logic in there is independent of
|
|
|
|
|
// SelectionDAG-specifics and a lot of work went in to optimize switch
|
|
|
|
|
// lowering in there.
|
|
|
|
|
|
|
|
|
|
const SwitchInst &SwInst = cast<SwitchInst>(U);
|
|
|
|
|
const unsigned SwCondValue = getOrCreateVReg(*SwInst.getCondition());
|
2017-01-18 06:13:50 +08:00
|
|
|
|
const BasicBlock *OrigBB = SwInst.getParent();
|
2017-01-05 19:28:51 +08:00
|
|
|
|
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
|
LLT LLTi1 = getLLTForType(*Type::getInt1Ty(U.getContext()), *DL);
|
2017-01-05 19:28:51 +08:00
|
|
|
|
for (auto &CaseIt : SwInst.cases()) {
|
|
|
|
|
const unsigned CaseValueReg = getOrCreateVReg(*CaseIt.getCaseValue());
|
|
|
|
|
const unsigned Tst = MRI->createGenericVirtualRegister(LLTi1);
|
|
|
|
|
MIRBuilder.buildICmp(CmpInst::ICMP_EQ, Tst, CaseValueReg, SwCondValue);
|
2017-01-18 06:13:50 +08:00
|
|
|
|
MachineBasicBlock &CurMBB = MIRBuilder.getMBB();
|
|
|
|
|
const BasicBlock *TrueBB = CaseIt.getCaseSuccessor();
|
2017-03-16 02:22:33 +08:00
|
|
|
|
MachineBasicBlock &TrueMBB = getMBB(*TrueBB);
|
2017-01-05 19:28:51 +08:00
|
|
|
|
|
2017-01-18 06:13:50 +08:00
|
|
|
|
MIRBuilder.buildBrCond(Tst, TrueMBB);
|
|
|
|
|
CurMBB.addSuccessor(&TrueMBB);
|
|
|
|
|
addMachineCFGPred({OrigBB, TrueBB}, &CurMBB);
|
2017-01-05 19:28:51 +08:00
|
|
|
|
|
2017-01-18 06:13:50 +08:00
|
|
|
|
MachineBasicBlock *FalseMBB =
|
2017-01-05 19:28:51 +08:00
|
|
|
|
MF->CreateMachineBasicBlock(SwInst.getParent());
|
2017-03-16 02:22:37 +08:00
|
|
|
|
// Insert the comparison blocks one after the other.
|
|
|
|
|
MF->insert(std::next(CurMBB.getIterator()), FalseMBB);
|
2017-01-18 06:13:50 +08:00
|
|
|
|
MIRBuilder.buildBr(*FalseMBB);
|
|
|
|
|
CurMBB.addSuccessor(FalseMBB);
|
2017-01-05 19:28:51 +08:00
|
|
|
|
|
2017-01-18 06:13:50 +08:00
|
|
|
|
MIRBuilder.setMBB(*FalseMBB);
|
2017-01-05 19:28:51 +08:00
|
|
|
|
}
|
|
|
|
|
// handle default case
|
2017-01-18 06:13:50 +08:00
|
|
|
|
const BasicBlock *DefaultBB = SwInst.getDefaultDest();
|
2017-03-16 02:22:33 +08:00
|
|
|
|
MachineBasicBlock &DefaultMBB = getMBB(*DefaultBB);
|
2017-01-18 06:13:50 +08:00
|
|
|
|
MIRBuilder.buildBr(DefaultMBB);
|
|
|
|
|
MachineBasicBlock &CurMBB = MIRBuilder.getMBB();
|
|
|
|
|
CurMBB.addSuccessor(&DefaultMBB);
|
|
|
|
|
addMachineCFGPred({OrigBB, DefaultBB}, &CurMBB);
|
2017-01-05 19:28:51 +08:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-30 17:13:18 +08:00
|
|
|
|
bool IRTranslator::translateIndirectBr(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
const IndirectBrInst &BrInst = cast<IndirectBrInst>(U);
|
|
|
|
|
|
|
|
|
|
const unsigned Tgt = getOrCreateVReg(*BrInst.getAddress());
|
|
|
|
|
MIRBuilder.buildBrIndirect(Tgt);
|
|
|
|
|
|
|
|
|
|
// Link successors.
|
|
|
|
|
MachineBasicBlock &CurBB = MIRBuilder.getMBB();
|
2018-08-26 16:41:15 +08:00
|
|
|
|
for (const BasicBlock *Succ : successors(&BrInst))
|
2017-03-16 02:22:33 +08:00
|
|
|
|
CurBB.addSuccessor(&getMBB(*Succ));
|
2017-01-30 17:13:18 +08:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateLoad(const User &U, MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
|
const LoadInst &LI = cast<LoadInst>(U);
|
2016-08-27 07:49:05 +08:00
|
|
|
|
|
2016-10-19 23:55:06 +08:00
|
|
|
|
auto Flags = LI.isVolatile() ? MachineMemOperand::MOVolatile
|
|
|
|
|
: MachineMemOperand::MONone;
|
|
|
|
|
Flags |= MachineMemOperand::MOLoad;
|
2016-07-27 04:23:26 +08:00
|
|
|
|
|
2017-12-01 04:06:02 +08:00
|
|
|
|
if (DL->getTypeStoreSize(LI.getType()) == 0)
|
|
|
|
|
return true;
|
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
ArrayRef<unsigned> Regs = getOrCreateVRegs(LI);
|
|
|
|
|
ArrayRef<uint64_t> Offsets = *VMap.getOffsets(LI);
|
|
|
|
|
unsigned Base = getOrCreateVReg(*LI.getPointerOperand());
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < Regs.size(); ++i) {
|
|
|
|
|
unsigned Addr = 0;
|
|
|
|
|
MIRBuilder.materializeGEP(Addr, Base, LLT::scalar(64), Offsets[i] / 8);
|
|
|
|
|
|
|
|
|
|
MachinePointerInfo Ptr(LI.getPointerOperand(), Offsets[i] / 8);
|
|
|
|
|
unsigned BaseAlign = getMemOpAlignment(LI);
|
|
|
|
|
auto MMO = MF->getMachineMemOperand(
|
|
|
|
|
Ptr, Flags, (MRI->getType(Regs[i]).getSizeInBits() + 7) / 8,
|
|
|
|
|
MinAlign(BaseAlign, Offsets[i] / 8), AAMDNodes(), nullptr,
|
|
|
|
|
LI.getSyncScopeID(), LI.getOrdering());
|
|
|
|
|
MIRBuilder.buildLoad(Regs[i], Addr, *MMO);
|
|
|
|
|
}
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
|
|
2016-07-27 04:23:26 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateStore(const User &U, MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
|
const StoreInst &SI = cast<StoreInst>(U);
|
2016-10-19 23:55:06 +08:00
|
|
|
|
auto Flags = SI.isVolatile() ? MachineMemOperand::MOVolatile
|
|
|
|
|
: MachineMemOperand::MONone;
|
|
|
|
|
Flags |= MachineMemOperand::MOStore;
|
2016-07-27 04:23:26 +08:00
|
|
|
|
|
2017-12-01 04:06:02 +08:00
|
|
|
|
if (DL->getTypeStoreSize(SI.getValueOperand()->getType()) == 0)
|
|
|
|
|
return true;
|
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
ArrayRef<unsigned> Vals = getOrCreateVRegs(*SI.getValueOperand());
|
|
|
|
|
ArrayRef<uint64_t> Offsets = *VMap.getOffsets(*SI.getValueOperand());
|
|
|
|
|
unsigned Base = getOrCreateVReg(*SI.getPointerOperand());
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < Vals.size(); ++i) {
|
|
|
|
|
unsigned Addr = 0;
|
|
|
|
|
MIRBuilder.materializeGEP(Addr, Base, LLT::scalar(64), Offsets[i] / 8);
|
|
|
|
|
|
|
|
|
|
MachinePointerInfo Ptr(SI.getPointerOperand(), Offsets[i] / 8);
|
|
|
|
|
unsigned BaseAlign = getMemOpAlignment(SI);
|
|
|
|
|
auto MMO = MF->getMachineMemOperand(
|
|
|
|
|
Ptr, Flags, (MRI->getType(Vals[i]).getSizeInBits() + 7) / 8,
|
|
|
|
|
MinAlign(BaseAlign, Offsets[i] / 8), AAMDNodes(), nullptr,
|
|
|
|
|
SI.getSyncScopeID(), SI.getOrdering());
|
|
|
|
|
MIRBuilder.buildStore(Vals[i], Addr, *MMO);
|
|
|
|
|
}
|
2016-07-27 04:23:26 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
static uint64_t getOffsetFromIndices(const User &U, const DataLayout &DL) {
|
2016-08-20 04:09:03 +08:00
|
|
|
|
const Value *Src = U.getOperand(0);
|
|
|
|
|
Type *Int32Ty = Type::getInt32Ty(U.getContext());
|
2017-05-19 17:47:02 +08:00
|
|
|
|
|
2016-08-20 01:47:05 +08:00
|
|
|
|
// getIndexedOffsetInType is designed for GEPs, so the first index is the
|
|
|
|
|
// usual array element rather than looking into the actual aggregate.
|
2018-05-16 18:32:02 +08:00
|
|
|
|
SmallVector<Value *, 1> Indices;
|
2016-08-20 01:47:05 +08:00
|
|
|
|
Indices.push_back(ConstantInt::get(Int32Ty, 0));
|
2016-08-20 04:09:03 +08:00
|
|
|
|
|
|
|
|
|
if (const ExtractValueInst *EVI = dyn_cast<ExtractValueInst>(&U)) {
|
|
|
|
|
for (auto Idx : EVI->indices())
|
|
|
|
|
Indices.push_back(ConstantInt::get(Int32Ty, Idx));
|
2018-05-16 18:32:02 +08:00
|
|
|
|
} else if (const InsertValueInst *IVI = dyn_cast<InsertValueInst>(&U)) {
|
|
|
|
|
for (auto Idx : IVI->indices())
|
|
|
|
|
Indices.push_back(ConstantInt::get(Int32Ty, Idx));
|
2016-08-20 04:09:03 +08:00
|
|
|
|
} else {
|
|
|
|
|
for (unsigned i = 1; i < U.getNumOperands(); ++i)
|
|
|
|
|
Indices.push_back(U.getOperand(i));
|
|
|
|
|
}
|
2016-08-20 01:47:05 +08:00
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
return 8 * static_cast<uint64_t>(
|
|
|
|
|
DL.getIndexedOffsetInType(Src->getType(), Indices));
|
|
|
|
|
}
|
2016-08-20 01:47:05 +08:00
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
bool IRTranslator::translateExtractValue(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
const Value *Src = U.getOperand(0);
|
|
|
|
|
uint64_t Offset = getOffsetFromIndices(U, *DL);
|
|
|
|
|
ArrayRef<unsigned> SrcRegs = getOrCreateVRegs(*Src);
|
|
|
|
|
ArrayRef<uint64_t> Offsets = *VMap.getOffsets(*Src);
|
|
|
|
|
unsigned Idx = std::lower_bound(Offsets.begin(), Offsets.end(), Offset) -
|
|
|
|
|
Offsets.begin();
|
|
|
|
|
auto &DstRegs = allocateVRegs(U);
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < DstRegs.size(); ++i)
|
|
|
|
|
DstRegs[i] = SrcRegs[Idx++];
|
2016-08-20 01:47:05 +08:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateInsertValue(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-08-20 04:09:03 +08:00
|
|
|
|
const Value *Src = U.getOperand(0);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
uint64_t Offset = getOffsetFromIndices(U, *DL);
|
|
|
|
|
auto &DstRegs = allocateVRegs(U);
|
|
|
|
|
ArrayRef<uint64_t> DstOffsets = *VMap.getOffsets(U);
|
|
|
|
|
ArrayRef<unsigned> SrcRegs = getOrCreateVRegs(*Src);
|
|
|
|
|
ArrayRef<unsigned> InsertedRegs = getOrCreateVRegs(*U.getOperand(1));
|
|
|
|
|
auto InsertedIt = InsertedRegs.begin();
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < DstRegs.size(); ++i) {
|
|
|
|
|
if (DstOffsets[i] >= Offset && InsertedIt != InsertedRegs.end())
|
|
|
|
|
DstRegs[i] = *InsertedIt++;
|
|
|
|
|
else
|
|
|
|
|
DstRegs[i] = SrcRegs[i];
|
2016-08-20 04:09:03 +08:00
|
|
|
|
}
|
2016-08-20 04:08:55 +08:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateSelect(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2017-04-19 14:38:37 +08:00
|
|
|
|
unsigned Tst = getOrCreateVReg(*U.getOperand(0));
|
2018-05-16 18:32:02 +08:00
|
|
|
|
ArrayRef<unsigned> ResRegs = getOrCreateVRegs(U);
|
|
|
|
|
ArrayRef<unsigned> Op0Regs = getOrCreateVRegs(*U.getOperand(1));
|
|
|
|
|
ArrayRef<unsigned> Op1Regs = getOrCreateVRegs(*U.getOperand(2));
|
|
|
|
|
|
2018-12-19 01:54:52 +08:00
|
|
|
|
const SelectInst &SI = cast<SelectInst>(U);
|
2019-02-07 03:57:06 +08:00
|
|
|
|
uint16_t Flags = 0;
|
|
|
|
|
if (const CmpInst *Cmp = dyn_cast<CmpInst>(SI.getCondition()))
|
|
|
|
|
Flags = MachineInstr::copyFlagsFromInstruction(*Cmp);
|
|
|
|
|
|
2018-12-19 01:54:52 +08:00
|
|
|
|
for (unsigned i = 0; i < ResRegs.size(); ++i) {
|
2019-02-07 03:57:06 +08:00
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_SELECT, {ResRegs[i]},
|
|
|
|
|
{Tst, Op0Regs[i], Op1Regs[i]}, Flags);
|
2018-12-19 01:54:52 +08:00
|
|
|
|
}
|
2018-05-16 18:32:02 +08:00
|
|
|
|
|
2016-08-20 04:09:07 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateBitCast(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2017-03-08 04:53:06 +08:00
|
|
|
|
// If we're bitcasting to the source type, we can reuse the source vreg.
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
|
if (getLLTForType(*U.getOperand(0)->getType(), *DL) ==
|
|
|
|
|
getLLTForType(*U.getType(), *DL)) {
|
2017-03-08 04:53:06 +08:00
|
|
|
|
unsigned SrcReg = getOrCreateVReg(*U.getOperand(0));
|
2018-05-16 18:32:02 +08:00
|
|
|
|
auto &Regs = *VMap.getVRegs(U);
|
2017-03-08 04:53:06 +08:00
|
|
|
|
// If we already assigned a vreg for this bitcast, we can't change that.
|
|
|
|
|
// Emit a copy to satisfy the users we already emitted.
|
2018-05-16 18:32:02 +08:00
|
|
|
|
if (!Regs.empty())
|
|
|
|
|
MIRBuilder.buildCopy(Regs[0], SrcReg);
|
|
|
|
|
else {
|
|
|
|
|
Regs.push_back(SrcReg);
|
|
|
|
|
VMap.getOffsets(U)->push_back(0);
|
|
|
|
|
}
|
2016-07-26 05:01:29 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-12-08 05:29:15 +08:00
|
|
|
|
return translateCast(TargetOpcode::G_BITCAST, U, MIRBuilder);
|
2016-07-26 05:01:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateCast(unsigned Opcode, const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
|
unsigned Op = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
|
unsigned Res = getOrCreateVReg(U);
|
2016-09-09 19:46:34 +08:00
|
|
|
|
MIRBuilder.buildInstr(Opcode).addDef(Res).addUse(Op);
|
2016-07-26 05:01:29 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateGetElementPtr(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-09-12 19:20:22 +08:00
|
|
|
|
// FIXME: support vector GEPs.
|
|
|
|
|
if (U.getType()->isVectorTy())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
Value &Op0 = *U.getOperand(0);
|
|
|
|
|
unsigned BaseReg = getOrCreateVReg(Op0);
|
2017-03-16 03:21:11 +08:00
|
|
|
|
Type *PtrIRTy = Op0.getType();
|
|
|
|
|
LLT PtrTy = getLLTForType(*PtrIRTy, *DL);
|
|
|
|
|
Type *OffsetIRTy = DL->getIntPtrType(PtrIRTy);
|
|
|
|
|
LLT OffsetTy = getLLTForType(*OffsetIRTy, *DL);
|
2016-09-12 19:20:22 +08:00
|
|
|
|
|
|
|
|
|
int64_t Offset = 0;
|
|
|
|
|
for (gep_type_iterator GTI = gep_type_begin(&U), E = gep_type_end(&U);
|
|
|
|
|
GTI != E; ++GTI) {
|
|
|
|
|
const Value *Idx = GTI.getOperand();
|
2016-12-02 10:55:30 +08:00
|
|
|
|
if (StructType *StTy = GTI.getStructTypeOrNull()) {
|
2016-09-12 19:20:22 +08:00
|
|
|
|
unsigned Field = cast<Constant>(Idx)->getUniqueInteger().getZExtValue();
|
|
|
|
|
Offset += DL->getStructLayout(StTy)->getElementOffset(Field);
|
|
|
|
|
continue;
|
|
|
|
|
} else {
|
|
|
|
|
uint64_t ElementSize = DL->getTypeAllocSize(GTI.getIndexedType());
|
|
|
|
|
|
|
|
|
|
// If this is a scalar constant or a splat vector of constants,
|
|
|
|
|
// handle it quickly.
|
|
|
|
|
if (const auto *CI = dyn_cast<ConstantInt>(Idx)) {
|
|
|
|
|
Offset += ElementSize * CI->getSExtValue();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Offset != 0) {
|
|
|
|
|
unsigned NewBaseReg = MRI->createGenericVirtualRegister(PtrTy);
|
2017-03-16 03:21:11 +08:00
|
|
|
|
unsigned OffsetReg =
|
|
|
|
|
getOrCreateVReg(*ConstantInt::get(OffsetIRTy, Offset));
|
2016-09-12 19:20:22 +08:00
|
|
|
|
MIRBuilder.buildGEP(NewBaseReg, BaseReg, OffsetReg);
|
|
|
|
|
|
|
|
|
|
BaseReg = NewBaseReg;
|
|
|
|
|
Offset = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned IdxReg = getOrCreateVReg(*Idx);
|
|
|
|
|
if (MRI->getType(IdxReg) != OffsetTy) {
|
|
|
|
|
unsigned NewIdxReg = MRI->createGenericVirtualRegister(OffsetTy);
|
|
|
|
|
MIRBuilder.buildSExtOrTrunc(NewIdxReg, IdxReg);
|
|
|
|
|
IdxReg = NewIdxReg;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-05 10:56:28 +08:00
|
|
|
|
// N = N + Idx * ElementSize;
|
|
|
|
|
// Avoid doing it for ElementSize of 1.
|
|
|
|
|
unsigned GepOffsetReg;
|
|
|
|
|
if (ElementSize != 1) {
|
|
|
|
|
unsigned ElementSizeReg =
|
|
|
|
|
getOrCreateVReg(*ConstantInt::get(OffsetIRTy, ElementSize));
|
|
|
|
|
|
|
|
|
|
GepOffsetReg = MRI->createGenericVirtualRegister(OffsetTy);
|
|
|
|
|
MIRBuilder.buildMul(GepOffsetReg, ElementSizeReg, IdxReg);
|
|
|
|
|
} else
|
|
|
|
|
GepOffsetReg = IdxReg;
|
2016-09-12 19:20:22 +08:00
|
|
|
|
|
|
|
|
|
unsigned NewBaseReg = MRI->createGenericVirtualRegister(PtrTy);
|
2018-01-05 10:56:28 +08:00
|
|
|
|
MIRBuilder.buildGEP(NewBaseReg, BaseReg, GepOffsetReg);
|
2016-09-12 19:20:22 +08:00
|
|
|
|
BaseReg = NewBaseReg;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Offset != 0) {
|
2017-03-16 03:21:11 +08:00
|
|
|
|
unsigned OffsetReg = getOrCreateVReg(*ConstantInt::get(OffsetIRTy, Offset));
|
2016-09-12 19:20:22 +08:00
|
|
|
|
MIRBuilder.buildGEP(getOrCreateVReg(U), BaseReg, OffsetReg);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildCopy(getOrCreateVReg(U), BaseReg);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-31 03:33:07 +08:00
|
|
|
|
bool IRTranslator::translateMemfunc(const CallInst &CI,
|
|
|
|
|
MachineIRBuilder &MIRBuilder,
|
|
|
|
|
unsigned ID) {
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
|
LLT SizeTy = getLLTForType(*CI.getArgOperand(2)->getType(), *DL);
|
2017-01-31 03:33:07 +08:00
|
|
|
|
Type *DstTy = CI.getArgOperand(0)->getType();
|
|
|
|
|
if (cast<PointerType>(DstTy)->getAddressSpace() != 0 ||
|
2016-10-19 04:03:45 +08:00
|
|
|
|
SizeTy.getSizeInBits() != DL->getPointerSizeInBits(0))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
SmallVector<CallLowering::ArgInfo, 8> Args;
|
|
|
|
|
for (int i = 0; i < 3; ++i) {
|
|
|
|
|
const auto &Arg = CI.getArgOperand(i);
|
|
|
|
|
Args.emplace_back(getOrCreateVReg(*Arg), Arg->getType());
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-31 03:33:07 +08:00
|
|
|
|
const char *Callee;
|
|
|
|
|
switch (ID) {
|
|
|
|
|
case Intrinsic::memmove:
|
|
|
|
|
case Intrinsic::memcpy: {
|
|
|
|
|
Type *SrcTy = CI.getArgOperand(1)->getType();
|
|
|
|
|
if(cast<PointerType>(SrcTy)->getAddressSpace() != 0)
|
|
|
|
|
return false;
|
|
|
|
|
Callee = ID == Intrinsic::memcpy ? "memcpy" : "memmove";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Intrinsic::memset:
|
|
|
|
|
Callee = "memset";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2016-10-19 04:03:45 +08:00
|
|
|
|
|
2017-03-20 22:40:18 +08:00
|
|
|
|
return CLI->lowerCall(MIRBuilder, CI.getCallingConv(),
|
|
|
|
|
MachineOperand::CreateES(Callee),
|
2016-10-19 04:03:45 +08:00
|
|
|
|
CallLowering::ArgInfo(0, CI.getType()), Args);
|
|
|
|
|
}
|
2016-09-12 19:20:22 +08:00
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
void IRTranslator::getStackGuard(unsigned DstReg,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2017-01-28 05:31:24 +08:00
|
|
|
|
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
|
|
|
|
|
MRI->setRegClass(DstReg, TRI->getPointerRegClass(*MF));
|
2016-11-01 02:30:59 +08:00
|
|
|
|
auto MIB = MIRBuilder.buildInstr(TargetOpcode::LOAD_STACK_GUARD);
|
|
|
|
|
MIB.addDef(DstReg);
|
|
|
|
|
|
2016-12-08 05:17:47 +08:00
|
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
2017-12-16 06:22:58 +08:00
|
|
|
|
Value *Global = TLI.getSDagStackGuard(*MF->getFunction().getParent());
|
2016-11-01 02:30:59 +08:00
|
|
|
|
if (!Global)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
MachinePointerInfo MPInfo(Global);
|
|
|
|
|
auto Flags = MachineMemOperand::MOLoad | MachineMemOperand::MOInvariant |
|
|
|
|
|
MachineMemOperand::MODereferenceable;
|
2018-08-17 05:30:05 +08:00
|
|
|
|
MachineMemOperand *MemRef =
|
2016-12-08 05:17:47 +08:00
|
|
|
|
MF->getMachineMemOperand(MPInfo, Flags, DL->getPointerSizeInBits() / 8,
|
2017-11-15 14:17:32 +08:00
|
|
|
|
DL->getPointerABIAlignment(0));
|
2018-08-17 05:30:05 +08:00
|
|
|
|
MIB.setMemRefs({MemRef});
|
2016-11-01 02:30:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-09 06:44:00 +08:00
|
|
|
|
bool IRTranslator::translateOverflowIntrinsic(const CallInst &CI, unsigned Op,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2018-05-16 18:32:02 +08:00
|
|
|
|
ArrayRef<unsigned> ResRegs = getOrCreateVRegs(CI);
|
2018-08-29 02:54:10 +08:00
|
|
|
|
MIRBuilder.buildInstr(Op)
|
|
|
|
|
.addDef(ResRegs[0])
|
|
|
|
|
.addDef(ResRegs[1])
|
|
|
|
|
.addUse(getOrCreateVReg(*CI.getOperand(0)))
|
|
|
|
|
.addUse(getOrCreateVReg(*CI.getOperand(1)));
|
2016-12-09 06:44:00 +08:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-13 01:38:34 +08:00
|
|
|
|
unsigned IRTranslator::getSimpleIntrinsicOpcode(Intrinsic::ID ID) {
|
2019-02-07 01:25:54 +08:00
|
|
|
|
switch (ID) {
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2019-02-13 01:28:17 +08:00
|
|
|
|
case Intrinsic::bswap:
|
|
|
|
|
return TargetOpcode::G_BSWAP;
|
2019-02-07 01:25:54 +08:00
|
|
|
|
case Intrinsic::ceil:
|
|
|
|
|
return TargetOpcode::G_FCEIL;
|
|
|
|
|
case Intrinsic::cos:
|
|
|
|
|
return TargetOpcode::G_FCOS;
|
|
|
|
|
case Intrinsic::ctpop:
|
|
|
|
|
return TargetOpcode::G_CTPOP;
|
|
|
|
|
case Intrinsic::exp:
|
|
|
|
|
return TargetOpcode::G_FEXP;
|
|
|
|
|
case Intrinsic::exp2:
|
|
|
|
|
return TargetOpcode::G_FEXP2;
|
|
|
|
|
case Intrinsic::fabs:
|
|
|
|
|
return TargetOpcode::G_FABS;
|
2019-02-12 01:05:20 +08:00
|
|
|
|
case Intrinsic::canonicalize:
|
|
|
|
|
return TargetOpcode::G_FCANONICALIZE;
|
2019-02-12 01:16:32 +08:00
|
|
|
|
case Intrinsic::floor:
|
|
|
|
|
return TargetOpcode::G_FFLOOR;
|
2019-02-13 01:38:34 +08:00
|
|
|
|
case Intrinsic::fma:
|
|
|
|
|
return TargetOpcode::G_FMA;
|
2019-02-07 01:25:54 +08:00
|
|
|
|
case Intrinsic::log:
|
|
|
|
|
return TargetOpcode::G_FLOG;
|
|
|
|
|
case Intrinsic::log2:
|
|
|
|
|
return TargetOpcode::G_FLOG2;
|
|
|
|
|
case Intrinsic::log10:
|
|
|
|
|
return TargetOpcode::G_FLOG10;
|
2019-02-13 01:38:34 +08:00
|
|
|
|
case Intrinsic::pow:
|
|
|
|
|
return TargetOpcode::G_FPOW;
|
2019-02-07 01:25:54 +08:00
|
|
|
|
case Intrinsic::round:
|
|
|
|
|
return TargetOpcode::G_INTRINSIC_ROUND;
|
|
|
|
|
case Intrinsic::sin:
|
|
|
|
|
return TargetOpcode::G_FSIN;
|
|
|
|
|
case Intrinsic::sqrt:
|
|
|
|
|
return TargetOpcode::G_FSQRT;
|
|
|
|
|
case Intrinsic::trunc:
|
|
|
|
|
return TargetOpcode::G_INTRINSIC_TRUNC;
|
|
|
|
|
}
|
|
|
|
|
return Intrinsic::not_intrinsic;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-13 01:38:34 +08:00
|
|
|
|
bool IRTranslator::translateSimpleIntrinsic(const CallInst &CI,
|
|
|
|
|
Intrinsic::ID ID,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2019-02-07 01:25:54 +08:00
|
|
|
|
|
2019-02-13 01:38:34 +08:00
|
|
|
|
unsigned Op = getSimpleIntrinsicOpcode(ID);
|
2019-02-07 01:25:54 +08:00
|
|
|
|
|
2019-02-13 01:38:34 +08:00
|
|
|
|
// Is this a simple intrinsic?
|
2019-02-07 01:25:54 +08:00
|
|
|
|
if (Op == Intrinsic::not_intrinsic)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Yes. Let's translate it.
|
2019-02-13 01:38:34 +08:00
|
|
|
|
SmallVector<llvm::SrcOp, 4> VRegs;
|
|
|
|
|
for (auto &Arg : CI.arg_operands())
|
|
|
|
|
VRegs.push_back(getOrCreateVReg(*Arg));
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildInstr(Op, {getOrCreateVReg(CI)}, VRegs,
|
2019-02-07 03:57:06 +08:00
|
|
|
|
MachineInstr::copyFlagsFromInstruction(CI));
|
2019-02-07 01:25:54 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2019-02-07 01:25:54 +08:00
|
|
|
|
|
2019-02-13 01:38:34 +08:00
|
|
|
|
// If this is a simple intrinsic (that is, we just need to add a def of
|
|
|
|
|
// a vreg, and uses for each arg operand, then translate it.
|
|
|
|
|
if (translateSimpleIntrinsic(CI, ID, MIRBuilder))
|
2019-02-07 01:25:54 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
2016-08-20 01:17:06 +08:00
|
|
|
|
switch (ID) {
|
2016-12-09 06:44:00 +08:00
|
|
|
|
default:
|
|
|
|
|
break;
|
2017-02-11 03:10:38 +08:00
|
|
|
|
case Intrinsic::lifetime_start:
|
2019-01-29 03:22:29 +08:00
|
|
|
|
case Intrinsic::lifetime_end: {
|
|
|
|
|
// No stack colouring in O0, discard region information.
|
|
|
|
|
if (MF->getTarget().getOptLevel() == CodeGenOpt::None)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
unsigned Op = ID == Intrinsic::lifetime_start ? TargetOpcode::LIFETIME_START
|
|
|
|
|
: TargetOpcode::LIFETIME_END;
|
|
|
|
|
|
|
|
|
|
// Get the underlying objects for the location passed on the lifetime
|
|
|
|
|
// marker.
|
|
|
|
|
SmallVector<Value *, 4> Allocas;
|
|
|
|
|
GetUnderlyingObjects(CI.getArgOperand(1), Allocas, *DL);
|
|
|
|
|
|
|
|
|
|
// Iterate over each underlying object, creating lifetime markers for each
|
|
|
|
|
// static alloca. Quit if we find a non-static alloca.
|
|
|
|
|
for (Value *V : Allocas) {
|
|
|
|
|
AllocaInst *AI = dyn_cast<AllocaInst>(V);
|
|
|
|
|
if (!AI)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!AI->isStaticAlloca())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildInstr(Op).addFrameIndex(getOrCreateFrameIndex(*AI));
|
|
|
|
|
}
|
2017-02-11 03:10:38 +08:00
|
|
|
|
return true;
|
2019-01-29 03:22:29 +08:00
|
|
|
|
}
|
2017-01-27 07:39:14 +08:00
|
|
|
|
case Intrinsic::dbg_declare: {
|
|
|
|
|
const DbgDeclareInst &DI = cast<DbgDeclareInst>(CI);
|
|
|
|
|
assert(DI.getVariable() && "Missing variable");
|
|
|
|
|
|
|
|
|
|
const Value *Address = DI.getAddress();
|
|
|
|
|
if (!Address || isa<UndefValue>(Address)) {
|
2018-05-14 20:53:11 +08:00
|
|
|
|
LLVM_DEBUG(dbgs() << "Dropping debug info for " << DI << "\n");
|
2017-01-27 07:39:14 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(DI.getVariable()->isValidLocationForIntrinsic(
|
|
|
|
|
MIRBuilder.getDebugLoc()) &&
|
|
|
|
|
"Expected inlined-at fields to agree");
|
2017-03-10 05:12:06 +08:00
|
|
|
|
auto AI = dyn_cast<AllocaInst>(Address);
|
|
|
|
|
if (AI && AI->isStaticAlloca()) {
|
|
|
|
|
// Static allocas are tracked at the MF level, no need for DBG_VALUE
|
|
|
|
|
// instructions (in fact, they get ignored if they *do* exist).
|
|
|
|
|
MF->setVariableDbgInfo(DI.getVariable(), DI.getExpression(),
|
|
|
|
|
getOrCreateFrameIndex(*AI), DI.getDebugLoc());
|
[GlobalISel] Lower dbg.declare into indirect DBG_VALUE
Summary:
D31439 changed the semantics of dbg.declare to take the address of a
variable as the first argument, making it indirect. It specifically
updated FastISel for this change here:
https://reviews.llvm.org/D31439#change-WVArzi177jPl
GlobalISel needs to follow suit, or else it will be missing a level of
indirection in the generated debuginfo. This problem was seen in a Rust
debuginfo test on aarch64, since GlobalISel is used at -O0 for aarch64.
https://github.com/rust-lang/rust/issues/49807
https://bugzilla.redhat.com/show_bug.cgi?id=1611597
https://bugzilla.redhat.com/show_bug.cgi?id=1625768
Reviewers: dblaikie, aprantl, t.p.northover, javed.absar, rnk
Reviewed By: rnk
Subscribers: #debug-info, rovka, kristof.beyls, JDevlieghere, llvm-commits, tstellar
Differential Revision: https://reviews.llvm.org/D51749
llvm-svn: 341969
2018-09-12 01:52:01 +08:00
|
|
|
|
} else {
|
|
|
|
|
// A dbg.declare describes the address of a source variable, so lower it
|
|
|
|
|
// into an indirect DBG_VALUE.
|
|
|
|
|
MIRBuilder.buildIndirectDbgValue(getOrCreateVReg(*Address),
|
|
|
|
|
DI.getVariable(), DI.getExpression());
|
|
|
|
|
}
|
2016-12-09 06:44:13 +08:00
|
|
|
|
return true;
|
2017-01-27 07:39:14 +08:00
|
|
|
|
}
|
2018-08-17 23:22:04 +08:00
|
|
|
|
case Intrinsic::dbg_label: {
|
|
|
|
|
const DbgLabelInst &DI = cast<DbgLabelInst>(CI);
|
|
|
|
|
assert(DI.getLabel() && "Missing label");
|
|
|
|
|
|
|
|
|
|
assert(DI.getLabel()->isValidLocationForIntrinsic(
|
|
|
|
|
MIRBuilder.getDebugLoc()) &&
|
|
|
|
|
"Expected inlined-at fields to agree");
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildDbgLabel(DI.getLabel());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-02-08 04:08:59 +08:00
|
|
|
|
case Intrinsic::vaend:
|
|
|
|
|
// No target I know of cares about va_end. Certainly no in-tree target
|
|
|
|
|
// does. Simplest intrinsic ever!
|
|
|
|
|
return true;
|
2017-02-09 01:57:20 +08:00
|
|
|
|
case Intrinsic::vastart: {
|
|
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
|
Value *Ptr = CI.getArgOperand(0);
|
|
|
|
|
unsigned ListSize = TLI.getVaListSizeInBits(*DL) / 8;
|
|
|
|
|
|
2019-01-31 09:38:47 +08:00
|
|
|
|
// FIXME: Get alignment
|
2017-02-09 01:57:20 +08:00
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_VASTART)
|
|
|
|
|
.addUse(getOrCreateVReg(*Ptr))
|
|
|
|
|
.addMemOperand(MF->getMachineMemOperand(
|
2019-01-31 09:38:47 +08:00
|
|
|
|
MachinePointerInfo(Ptr), MachineMemOperand::MOStore, ListSize, 1));
|
2017-02-09 01:57:20 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-01-27 07:39:14 +08:00
|
|
|
|
case Intrinsic::dbg_value: {
|
|
|
|
|
// This form of DBG_VALUE is target-independent.
|
|
|
|
|
const DbgValueInst &DI = cast<DbgValueInst>(CI);
|
|
|
|
|
const Value *V = DI.getValue();
|
|
|
|
|
assert(DI.getVariable()->isValidLocationForIntrinsic(
|
|
|
|
|
MIRBuilder.getDebugLoc()) &&
|
|
|
|
|
"Expected inlined-at fields to agree");
|
|
|
|
|
if (!V) {
|
|
|
|
|
// Currently the optimizer can produce this; insert an undef to
|
|
|
|
|
// help debugging. Probably the optimizer should not do this.
|
2017-07-29 06:46:20 +08:00
|
|
|
|
MIRBuilder.buildIndirectDbgValue(0, DI.getVariable(), DI.getExpression());
|
2017-01-27 07:39:14 +08:00
|
|
|
|
} else if (const auto *CI = dyn_cast<Constant>(V)) {
|
2017-07-29 06:46:20 +08:00
|
|
|
|
MIRBuilder.buildConstDbgValue(*CI, DI.getVariable(), DI.getExpression());
|
2017-01-27 07:39:14 +08:00
|
|
|
|
} else {
|
|
|
|
|
unsigned Reg = getOrCreateVReg(*V);
|
|
|
|
|
// FIXME: This does not handle register-indirect values at offset 0. The
|
|
|
|
|
// direct/indirect thing shouldn't really be handled by something as
|
|
|
|
|
// implicit as reg+noreg vs reg+imm in the first palce, but it seems
|
|
|
|
|
// pretty baked in right now.
|
2017-07-29 04:21:02 +08:00
|
|
|
|
MIRBuilder.buildDirectDbgValue(Reg, DI.getVariable(), DI.getExpression());
|
2017-01-27 07:39:14 +08:00
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-12-09 06:44:00 +08:00
|
|
|
|
case Intrinsic::uadd_with_overflow:
|
2018-08-29 02:54:10 +08:00
|
|
|
|
return translateOverflowIntrinsic(CI, TargetOpcode::G_UADDO, MIRBuilder);
|
2016-12-09 06:44:00 +08:00
|
|
|
|
case Intrinsic::sadd_with_overflow:
|
|
|
|
|
return translateOverflowIntrinsic(CI, TargetOpcode::G_SADDO, MIRBuilder);
|
|
|
|
|
case Intrinsic::usub_with_overflow:
|
2018-08-29 02:54:10 +08:00
|
|
|
|
return translateOverflowIntrinsic(CI, TargetOpcode::G_USUBO, MIRBuilder);
|
2016-12-09 06:44:00 +08:00
|
|
|
|
case Intrinsic::ssub_with_overflow:
|
|
|
|
|
return translateOverflowIntrinsic(CI, TargetOpcode::G_SSUBO, MIRBuilder);
|
|
|
|
|
case Intrinsic::umul_with_overflow:
|
|
|
|
|
return translateOverflowIntrinsic(CI, TargetOpcode::G_UMULO, MIRBuilder);
|
|
|
|
|
case Intrinsic::smul_with_overflow:
|
|
|
|
|
return translateOverflowIntrinsic(CI, TargetOpcode::G_SMULO, MIRBuilder);
|
2018-02-13 08:47:46 +08:00
|
|
|
|
case Intrinsic::fmuladd: {
|
|
|
|
|
const TargetMachine &TM = MF->getTarget();
|
|
|
|
|
const TargetLowering &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
|
unsigned Dst = getOrCreateVReg(CI);
|
|
|
|
|
unsigned Op0 = getOrCreateVReg(*CI.getArgOperand(0));
|
|
|
|
|
unsigned Op1 = getOrCreateVReg(*CI.getArgOperand(1));
|
|
|
|
|
unsigned Op2 = getOrCreateVReg(*CI.getArgOperand(2));
|
|
|
|
|
if (TM.Options.AllowFPOpFusion != FPOpFusion::Strict &&
|
|
|
|
|
TLI.isFMAFasterThanFMulAndFAdd(TLI.getValueType(*DL, CI.getType()))) {
|
|
|
|
|
// TODO: Revisit this to see if we should move this part of the
|
|
|
|
|
// lowering to the combiner.
|
2019-02-07 03:57:06 +08:00
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FMA, {Dst}, {Op0, Op1, Op2},
|
|
|
|
|
MachineInstr::copyFlagsFromInstruction(CI));
|
2018-02-13 08:47:46 +08:00
|
|
|
|
} else {
|
|
|
|
|
LLT Ty = getLLTForType(*CI.getType(), *DL);
|
2019-02-07 03:57:06 +08:00
|
|
|
|
auto FMul = MIRBuilder.buildInstr(TargetOpcode::G_FMUL, {Ty}, {Op0, Op1},
|
|
|
|
|
MachineInstr::copyFlagsFromInstruction(CI));
|
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FADD, {Dst}, {FMul, Op2},
|
|
|
|
|
MachineInstr::copyFlagsFromInstruction(CI));
|
2018-02-13 08:47:46 +08:00
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-10-19 04:03:45 +08:00
|
|
|
|
case Intrinsic::memcpy:
|
2017-01-31 03:33:07 +08:00
|
|
|
|
case Intrinsic::memmove:
|
|
|
|
|
case Intrinsic::memset:
|
|
|
|
|
return translateMemfunc(CI, MIRBuilder, ID);
|
2016-11-10 06:39:54 +08:00
|
|
|
|
case Intrinsic::eh_typeid_for: {
|
|
|
|
|
GlobalValue *GV = ExtractTypeInfo(CI.getArgOperand(0));
|
|
|
|
|
unsigned Reg = getOrCreateVReg(CI);
|
2016-12-08 05:17:47 +08:00
|
|
|
|
unsigned TypeID = MF->getTypeIDFor(GV);
|
2016-11-10 06:39:54 +08:00
|
|
|
|
MIRBuilder.buildConstant(Reg, TypeID);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-10-19 04:03:51 +08:00
|
|
|
|
case Intrinsic::objectsize: {
|
|
|
|
|
// If we don't know by now, we're never going to know.
|
|
|
|
|
const ConstantInt *Min = cast<ConstantInt>(CI.getArgOperand(1));
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildConstant(getOrCreateVReg(CI), Min->isZero() ? -1ULL : 0);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-11-07 23:24:12 +08:00
|
|
|
|
case Intrinsic::is_constant:
|
|
|
|
|
// If this wasn't constant-folded away by now, then it's not a
|
|
|
|
|
// constant.
|
|
|
|
|
MIRBuilder.buildConstant(getOrCreateVReg(CI), 0);
|
|
|
|
|
return true;
|
2016-11-01 02:30:59 +08:00
|
|
|
|
case Intrinsic::stackguard:
|
2016-12-08 05:29:15 +08:00
|
|
|
|
getStackGuard(getOrCreateVReg(CI), MIRBuilder);
|
2016-11-01 02:30:59 +08:00
|
|
|
|
return true;
|
|
|
|
|
case Intrinsic::stackprotector: {
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
|
LLT PtrTy = getLLTForType(*CI.getArgOperand(0)->getType(), *DL);
|
2016-11-01 02:30:59 +08:00
|
|
|
|
unsigned GuardVal = MRI->createGenericVirtualRegister(PtrTy);
|
2016-12-08 05:29:15 +08:00
|
|
|
|
getStackGuard(GuardVal, MIRBuilder);
|
2016-11-01 02:30:59 +08:00
|
|
|
|
|
|
|
|
|
AllocaInst *Slot = cast<AllocaInst>(CI.getArgOperand(1));
|
2018-12-10 23:15:05 +08:00
|
|
|
|
int FI = getOrCreateFrameIndex(*Slot);
|
|
|
|
|
MF->getFrameInfo().setStackProtectorIndex(FI);
|
|
|
|
|
|
2016-11-01 02:30:59 +08:00
|
|
|
|
MIRBuilder.buildStore(
|
|
|
|
|
GuardVal, getOrCreateVReg(*Slot),
|
2018-12-10 23:15:05 +08:00
|
|
|
|
*MF->getMachineMemOperand(MachinePointerInfo::getFixedStack(*MF, FI),
|
|
|
|
|
MachineMemOperand::MOStore |
|
|
|
|
|
MachineMemOperand::MOVolatile,
|
|
|
|
|
PtrTy.getSizeInBits() / 8, 8));
|
2016-11-01 02:30:59 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2019-04-03 06:46:31 +08:00
|
|
|
|
case Intrinsic::stacksave: {
|
|
|
|
|
// Save the stack pointer to the location provided by the intrinsic.
|
|
|
|
|
unsigned Reg = getOrCreateVReg(CI);
|
|
|
|
|
unsigned StackPtr = MF->getSubtarget()
|
|
|
|
|
.getTargetLowering()
|
|
|
|
|
->getStackPointerRegisterToSaveRestore();
|
|
|
|
|
|
|
|
|
|
// If the target doesn't specify a stack pointer, then fall back.
|
|
|
|
|
if (!StackPtr)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildCopy(Reg, StackPtr);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case Intrinsic::stackrestore: {
|
|
|
|
|
// Restore the stack pointer from the location provided by the intrinsic.
|
|
|
|
|
unsigned Reg = getOrCreateVReg(*CI.getArgOperand(0));
|
|
|
|
|
unsigned StackPtr = MF->getSubtarget()
|
|
|
|
|
.getTargetLowering()
|
|
|
|
|
->getStackPointerRegisterToSaveRestore();
|
|
|
|
|
|
|
|
|
|
// If the target doesn't specify a stack pointer, then fall back.
|
|
|
|
|
if (!StackPtr)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildCopy(StackPtr, Reg);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-08-04 09:22:12 +08:00
|
|
|
|
case Intrinsic::cttz:
|
|
|
|
|
case Intrinsic::ctlz: {
|
|
|
|
|
ConstantInt *Cst = cast<ConstantInt>(CI.getArgOperand(1));
|
|
|
|
|
bool isTrailing = ID == Intrinsic::cttz;
|
|
|
|
|
unsigned Opcode = isTrailing
|
|
|
|
|
? Cst->isZero() ? TargetOpcode::G_CTTZ
|
|
|
|
|
: TargetOpcode::G_CTTZ_ZERO_UNDEF
|
|
|
|
|
: Cst->isZero() ? TargetOpcode::G_CTLZ
|
|
|
|
|
: TargetOpcode::G_CTLZ_ZERO_UNDEF;
|
|
|
|
|
MIRBuilder.buildInstr(Opcode)
|
|
|
|
|
.addDef(getOrCreateVReg(CI))
|
|
|
|
|
.addUse(getOrCreateVReg(*CI.getArgOperand(0)));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-10-06 05:02:46 +08:00
|
|
|
|
case Intrinsic::invariant_start: {
|
|
|
|
|
LLT PtrTy = getLLTForType(*CI.getArgOperand(0)->getType(), *DL);
|
|
|
|
|
unsigned Undef = MRI->createGenericVirtualRegister(PtrTy);
|
|
|
|
|
MIRBuilder.buildUndef(Undef);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case Intrinsic::invariant_end:
|
|
|
|
|
return true;
|
2016-08-20 01:17:06 +08:00
|
|
|
|
}
|
2016-12-09 06:44:00 +08:00
|
|
|
|
return false;
|
2016-08-20 01:17:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-10 07:36:26 +08:00
|
|
|
|
bool IRTranslator::translateInlineAsm(const CallInst &CI,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
const InlineAsm &IA = cast<InlineAsm>(*CI.getCalledValue());
|
|
|
|
|
if (!IA.getConstraintString().empty())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
unsigned ExtraInfo = 0;
|
|
|
|
|
if (IA.hasSideEffects())
|
|
|
|
|
ExtraInfo |= InlineAsm::Extra_HasSideEffects;
|
|
|
|
|
if (IA.getDialect() == InlineAsm::AD_Intel)
|
|
|
|
|
ExtraInfo |= InlineAsm::Extra_AsmDialect;
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::INLINEASM)
|
|
|
|
|
.addExternalSymbol(IA.getAsmString().c_str())
|
|
|
|
|
.addImm(ExtraInfo);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
unsigned IRTranslator::packRegs(const Value &V,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
ArrayRef<unsigned> Regs = getOrCreateVRegs(V);
|
|
|
|
|
ArrayRef<uint64_t> Offsets = *VMap.getOffsets(V);
|
|
|
|
|
LLT BigTy = getLLTForType(*V.getType(), *DL);
|
|
|
|
|
|
|
|
|
|
if (Regs.size() == 1)
|
|
|
|
|
return Regs[0];
|
|
|
|
|
|
|
|
|
|
unsigned Dst = MRI->createGenericVirtualRegister(BigTy);
|
|
|
|
|
MIRBuilder.buildUndef(Dst);
|
|
|
|
|
for (unsigned i = 0; i < Regs.size(); ++i) {
|
|
|
|
|
unsigned NewDst = MRI->createGenericVirtualRegister(BigTy);
|
|
|
|
|
MIRBuilder.buildInsert(NewDst, Dst, Regs[i], Offsets[i]);
|
|
|
|
|
Dst = NewDst;
|
|
|
|
|
}
|
|
|
|
|
return Dst;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRTranslator::unpackRegs(const Value &V, unsigned Src,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
ArrayRef<unsigned> Regs = getOrCreateVRegs(V);
|
|
|
|
|
ArrayRef<uint64_t> Offsets = *VMap.getOffsets(V);
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < Regs.size(); ++i)
|
|
|
|
|
MIRBuilder.buildExtract(Regs[i], Src, Offsets[i]);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateCall(const User &U, MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
|
const CallInst &CI = cast<CallInst>(U);
|
2016-12-08 05:17:47 +08:00
|
|
|
|
auto TII = MF->getTarget().getIntrinsicInfo();
|
2016-08-11 05:44:01 +08:00
|
|
|
|
const Function *F = CI.getCalledFunction();
|
|
|
|
|
|
2018-01-31 03:50:58 +08:00
|
|
|
|
// FIXME: support Windows dllimport function calls.
|
|
|
|
|
if (F && F->hasDLLImportStorageClass())
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-01-20 07:59:35 +08:00
|
|
|
|
if (CI.isInlineAsm())
|
2017-03-10 07:36:26 +08:00
|
|
|
|
return translateInlineAsm(CI, MIRBuilder);
|
2017-01-20 07:59:35 +08:00
|
|
|
|
|
2018-01-03 02:56:39 +08:00
|
|
|
|
Intrinsic::ID ID = Intrinsic::not_intrinsic;
|
|
|
|
|
if (F && F->isIntrinsic()) {
|
|
|
|
|
ID = F->getIntrinsicID();
|
|
|
|
|
if (TII && ID == Intrinsic::not_intrinsic)
|
|
|
|
|
ID = static_cast<Intrinsic::ID>(TII->getIntrinsicID(F));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!F || !F->isIntrinsic() || ID == Intrinsic::not_intrinsic) {
|
2019-03-14 22:18:56 +08:00
|
|
|
|
bool IsSplitType = valueIsSplit(CI);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
unsigned Res = IsSplitType ? MRI->createGenericVirtualRegister(
|
|
|
|
|
getLLTForType(*CI.getType(), *DL))
|
|
|
|
|
: getOrCreateVReg(CI);
|
|
|
|
|
|
2016-08-11 05:44:01 +08:00
|
|
|
|
SmallVector<unsigned, 8> Args;
|
|
|
|
|
for (auto &Arg: CI.arg_operands())
|
2018-05-16 18:32:02 +08:00
|
|
|
|
Args.push_back(packRegs(*Arg, MIRBuilder));
|
2016-08-11 05:44:01 +08:00
|
|
|
|
|
2017-03-10 06:00:39 +08:00
|
|
|
|
MF->getFrameInfo().setHasCalls(true);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
bool Success = CLI->lowerCall(MIRBuilder, &CI, Res, Args, [&]() {
|
2016-08-30 03:07:08 +08:00
|
|
|
|
return getOrCreateVReg(*CI.getCalledValue());
|
|
|
|
|
});
|
2018-05-16 18:32:02 +08:00
|
|
|
|
|
|
|
|
|
if (IsSplitType)
|
|
|
|
|
unpackRegs(CI, Res, MIRBuilder);
|
|
|
|
|
return Success;
|
2016-08-11 05:44:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(ID != Intrinsic::not_intrinsic && "unknown intrinsic");
|
2016-07-30 06:32:36 +08:00
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
if (translateKnownIntrinsic(CI, ID, MIRBuilder))
|
2016-08-20 01:17:06 +08:00
|
|
|
|
return true;
|
|
|
|
|
|
2019-03-14 22:18:56 +08:00
|
|
|
|
ArrayRef<unsigned> ResultRegs;
|
|
|
|
|
if (!CI.getType()->isVoidTy())
|
|
|
|
|
ResultRegs = getOrCreateVRegs(CI);
|
|
|
|
|
|
2016-07-30 06:32:36 +08:00
|
|
|
|
MachineInstrBuilder MIB =
|
2019-03-14 22:18:56 +08:00
|
|
|
|
MIRBuilder.buildIntrinsic(ID, ResultRegs, !CI.doesNotAccessMemory());
|
2016-07-30 06:32:36 +08:00
|
|
|
|
|
|
|
|
|
for (auto &Arg : CI.arg_operands()) {
|
2017-03-08 04:53:09 +08:00
|
|
|
|
// Some intrinsics take metadata parameters. Reject them.
|
|
|
|
|
if (isa<MetadataAsValue>(Arg))
|
|
|
|
|
return false;
|
2018-05-16 18:32:02 +08:00
|
|
|
|
MIB.addUse(packRegs(*Arg, MIRBuilder));
|
2016-07-30 06:32:36 +08:00
|
|
|
|
}
|
2017-06-06 06:17:17 +08:00
|
|
|
|
|
|
|
|
|
// Add a MachineMemOperand if it is a target mem intrinsic.
|
|
|
|
|
const TargetLowering &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
|
TargetLowering::IntrinsicInfo Info;
|
|
|
|
|
// TODO: Add a GlobalISel version of getTgtMemIntrinsic.
|
2017-12-15 06:34:10 +08:00
|
|
|
|
if (TLI.getTgtMemIntrinsic(Info, CI, *MF, ID)) {
|
2019-02-01 07:41:23 +08:00
|
|
|
|
unsigned Align = Info.align;
|
|
|
|
|
if (Align == 0)
|
|
|
|
|
Align = DL->getABITypeAlignment(Info.memVT.getTypeForEVT(F->getContext()));
|
2019-01-31 09:38:47 +08:00
|
|
|
|
|
2019-02-01 07:41:23 +08:00
|
|
|
|
uint64_t Size = Info.memVT.getStoreSize();
|
2017-06-06 06:17:17 +08:00
|
|
|
|
MIB.addMemOperand(MF->getMachineMemOperand(MachinePointerInfo(Info.ptrVal),
|
2019-02-01 07:41:23 +08:00
|
|
|
|
Info.flags, Size, Align));
|
2017-06-06 06:17:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-30 06:32:36 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateInvoke(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-11-10 06:39:54 +08:00
|
|
|
|
const InvokeInst &I = cast<InvokeInst>(U);
|
2016-12-08 05:17:47 +08:00
|
|
|
|
MCContext &Context = MF->getContext();
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
|
|
|
|
const BasicBlock *ReturnBB = I.getSuccessor(0);
|
|
|
|
|
const BasicBlock *EHPadBB = I.getSuccessor(1);
|
|
|
|
|
|
2017-03-10 08:25:35 +08:00
|
|
|
|
const Value *Callee = I.getCalledValue();
|
2016-11-10 06:39:54 +08:00
|
|
|
|
const Function *Fn = dyn_cast<Function>(Callee);
|
|
|
|
|
if (isa<InlineAsm>(Callee))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// FIXME: support invoking patchpoint and statepoint intrinsics.
|
|
|
|
|
if (Fn && Fn->isIntrinsic())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// FIXME: support whatever these are.
|
|
|
|
|
if (I.countOperandBundlesOfType(LLVMContext::OB_deopt))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// FIXME: support Windows exception handling.
|
|
|
|
|
if (!isa<LandingPadInst>(EHPadBB->front()))
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-12-02 03:32:15 +08:00
|
|
|
|
// Emit the actual call, bracketed by EH_LABELs so that the MF knows about
|
2016-11-10 06:39:54 +08:00
|
|
|
|
// the region covered by the try.
|
2016-12-02 03:32:15 +08:00
|
|
|
|
MCSymbol *BeginSymbol = Context.createTempSymbol();
|
2016-11-10 06:39:54 +08:00
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(BeginSymbol);
|
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
unsigned Res =
|
|
|
|
|
MRI->createGenericVirtualRegister(getLLTForType(*I.getType(), *DL));
|
2017-02-01 02:36:11 +08:00
|
|
|
|
SmallVector<unsigned, 8> Args;
|
2016-11-10 06:39:54 +08:00
|
|
|
|
for (auto &Arg: I.arg_operands())
|
2018-05-16 18:32:02 +08:00
|
|
|
|
Args.push_back(packRegs(*Arg, MIRBuilder));
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
2017-03-10 08:25:44 +08:00
|
|
|
|
if (!CLI->lowerCall(MIRBuilder, &I, Res, Args,
|
2017-03-10 08:25:35 +08:00
|
|
|
|
[&]() { return getOrCreateVReg(*I.getCalledValue()); }))
|
|
|
|
|
return false;
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
unpackRegs(I, Res, MIRBuilder);
|
|
|
|
|
|
2016-12-02 03:32:15 +08:00
|
|
|
|
MCSymbol *EndSymbol = Context.createTempSymbol();
|
2016-11-10 06:39:54 +08:00
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::EH_LABEL).addSym(EndSymbol);
|
|
|
|
|
|
|
|
|
|
// FIXME: track probabilities.
|
2017-03-16 02:22:33 +08:00
|
|
|
|
MachineBasicBlock &EHPadMBB = getMBB(*EHPadBB),
|
|
|
|
|
&ReturnMBB = getMBB(*ReturnBB);
|
2016-12-08 05:17:47 +08:00
|
|
|
|
MF->addInvoke(&EHPadMBB, BeginSymbol, EndSymbol);
|
2016-11-10 06:39:54 +08:00
|
|
|
|
MIRBuilder.getMBB().addSuccessor(&ReturnMBB);
|
|
|
|
|
MIRBuilder.getMBB().addSuccessor(&EHPadMBB);
|
2017-02-01 04:12:18 +08:00
|
|
|
|
MIRBuilder.buildBr(ReturnMBB);
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-09 04:48:56 +08:00
|
|
|
|
bool IRTranslator::translateCallBr(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
// FIXME: Implement this.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateLandingPad(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2016-11-10 06:39:54 +08:00
|
|
|
|
const LandingPadInst &LP = cast<LandingPadInst>(U);
|
|
|
|
|
|
|
|
|
|
MachineBasicBlock &MBB = MIRBuilder.getMBB();
|
|
|
|
|
|
|
|
|
|
MBB.setIsEHPad();
|
|
|
|
|
|
|
|
|
|
// If there aren't registers to copy the values into (e.g., during SjLj
|
|
|
|
|
// exceptions), then don't bother.
|
2016-12-08 05:17:47 +08:00
|
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
2017-12-16 06:22:58 +08:00
|
|
|
|
const Constant *PersonalityFn = MF->getFunction().getPersonalityFn();
|
2016-11-10 06:39:54 +08:00
|
|
|
|
if (TLI.getExceptionPointerRegister(PersonalityFn) == 0 &&
|
|
|
|
|
TLI.getExceptionSelectorRegister(PersonalityFn) == 0)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// If landingpad's return type is token type, we don't create DAG nodes
|
|
|
|
|
// for its exception pointer and selector value. The extraction of exception
|
|
|
|
|
// pointer or selector value from token type landingpads is not currently
|
|
|
|
|
// supported.
|
|
|
|
|
if (LP.getType()->isTokenTy())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// Add a label to mark the beginning of the landing pad. Deletion of the
|
|
|
|
|
// landing pad can thus be detected via the MachineModuleInfo.
|
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::EH_LABEL)
|
2016-12-08 05:17:47 +08:00
|
|
|
|
.addSym(MF->addLandingPad(&MBB));
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
2017-03-08 07:32:10 +08:00
|
|
|
|
LLT Ty = getLLTForType(*LP.getType(), *DL);
|
2017-03-08 07:04:06 +08:00
|
|
|
|
unsigned Undef = MRI->createGenericVirtualRegister(Ty);
|
|
|
|
|
MIRBuilder.buildUndef(Undef);
|
|
|
|
|
|
2017-01-25 08:16:53 +08:00
|
|
|
|
SmallVector<LLT, 2> Tys;
|
|
|
|
|
for (Type *Ty : cast<StructType>(LP.getType())->elements())
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
|
Tys.push_back(getLLTForType(*Ty, *DL));
|
2017-01-25 08:16:53 +08:00
|
|
|
|
assert(Tys.size() == 2 && "Only two-valued landingpads are supported");
|
|
|
|
|
|
2016-11-10 06:39:54 +08:00
|
|
|
|
// Mark exception register as live in.
|
2017-03-08 07:04:06 +08:00
|
|
|
|
unsigned ExceptionReg = TLI.getExceptionPointerRegister(PersonalityFn);
|
|
|
|
|
if (!ExceptionReg)
|
|
|
|
|
return false;
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
2017-03-08 07:04:06 +08:00
|
|
|
|
MBB.addLiveIn(ExceptionReg);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
ArrayRef<unsigned> ResRegs = getOrCreateVRegs(LP);
|
|
|
|
|
MIRBuilder.buildCopy(ResRegs[0], ExceptionReg);
|
2017-03-08 07:04:06 +08:00
|
|
|
|
|
|
|
|
|
unsigned SelectorReg = TLI.getExceptionSelectorRegister(PersonalityFn);
|
|
|
|
|
if (!SelectorReg)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
MBB.addLiveIn(SelectorReg);
|
|
|
|
|
unsigned PtrVReg = MRI->createGenericVirtualRegister(Tys[0]);
|
|
|
|
|
MIRBuilder.buildCopy(PtrVReg, SelectorReg);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
MIRBuilder.buildCast(ResRegs[1], PtrVReg);
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-04 02:22:45 +08:00
|
|
|
|
bool IRTranslator::translateAlloca(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
auto &AI = cast<AllocaInst>(U);
|
|
|
|
|
|
2018-07-26 09:25:58 +08:00
|
|
|
|
if (AI.isSwiftError())
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-02-04 02:22:45 +08:00
|
|
|
|
if (AI.isStaticAlloca()) {
|
|
|
|
|
unsigned Res = getOrCreateVReg(AI);
|
|
|
|
|
int FI = getOrCreateFrameIndex(AI);
|
|
|
|
|
MIRBuilder.buildFrameIndex(Res, FI);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-17 22:26:32 +08:00
|
|
|
|
// FIXME: support stack probing for Windows.
|
|
|
|
|
if (MF->getTarget().getTargetTriple().isOSWindows())
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-02-04 02:22:45 +08:00
|
|
|
|
// Now we're in the harder dynamic case.
|
|
|
|
|
Type *Ty = AI.getAllocatedType();
|
|
|
|
|
unsigned Align =
|
|
|
|
|
std::max((unsigned)DL->getPrefTypeAlignment(Ty), AI.getAlignment());
|
|
|
|
|
|
|
|
|
|
unsigned NumElts = getOrCreateVReg(*AI.getArraySize());
|
|
|
|
|
|
2017-03-16 03:21:11 +08:00
|
|
|
|
Type *IntPtrIRTy = DL->getIntPtrType(AI.getType());
|
|
|
|
|
LLT IntPtrTy = getLLTForType(*IntPtrIRTy, *DL);
|
2017-02-04 02:22:45 +08:00
|
|
|
|
if (MRI->getType(NumElts) != IntPtrTy) {
|
|
|
|
|
unsigned ExtElts = MRI->createGenericVirtualRegister(IntPtrTy);
|
|
|
|
|
MIRBuilder.buildZExtOrTrunc(ExtElts, NumElts);
|
|
|
|
|
NumElts = ExtElts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned AllocSize = MRI->createGenericVirtualRegister(IntPtrTy);
|
2017-03-16 03:21:11 +08:00
|
|
|
|
unsigned TySize =
|
|
|
|
|
getOrCreateVReg(*ConstantInt::get(IntPtrIRTy, -DL->getTypeAllocSize(Ty)));
|
2017-02-04 02:22:45 +08:00
|
|
|
|
MIRBuilder.buildMul(AllocSize, NumElts, TySize);
|
|
|
|
|
|
Recommit: [globalisel] Change LLT constructor string into an LLT-based object that knows how to generate it.
Summary:
This will allow future patches to inspect the details of the LLT. The implementation is now split between
the Support and CodeGen libraries to allow TableGen to use this class without introducing layering concerns.
Thanks to Ahmed Bougacha for finding a reasonable way to avoid the layering issue and providing the version of this patch without that problem.
The problem with the previous commit appears to have been that TableGen was including CodeGen/LowLevelType.h instead of Support/LowLevelTypeImpl.h.
Reviewers: t.p.northover, qcolombet, rovka, aditya_nandakumar, ab, javed.absar
Subscribers: arsenm, nhaehnle, mgorny, dberris, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30046
llvm-svn: 297241
2017-03-08 07:20:35 +08:00
|
|
|
|
LLT PtrTy = getLLTForType(*AI.getType(), *DL);
|
2017-02-04 02:22:45 +08:00
|
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
|
unsigned SPReg = TLI.getStackPointerRegisterToSaveRestore();
|
|
|
|
|
|
|
|
|
|
unsigned SPTmp = MRI->createGenericVirtualRegister(PtrTy);
|
|
|
|
|
MIRBuilder.buildCopy(SPTmp, SPReg);
|
|
|
|
|
|
2017-02-15 04:56:18 +08:00
|
|
|
|
unsigned AllocTmp = MRI->createGenericVirtualRegister(PtrTy);
|
|
|
|
|
MIRBuilder.buildGEP(AllocTmp, SPTmp, AllocSize);
|
2017-02-04 02:22:45 +08:00
|
|
|
|
|
|
|
|
|
// Handle alignment. We have to realign if the allocation granule was smaller
|
|
|
|
|
// than stack alignment, or the specific alloca requires more than stack
|
|
|
|
|
// alignment.
|
|
|
|
|
unsigned StackAlign =
|
|
|
|
|
MF->getSubtarget().getFrameLowering()->getStackAlignment();
|
|
|
|
|
Align = std::max(Align, StackAlign);
|
|
|
|
|
if (Align > StackAlign || DL->getTypeAllocSize(Ty) % StackAlign != 0) {
|
|
|
|
|
// Round the size of the allocation up to the stack alignment size
|
|
|
|
|
// by add SA-1 to the size. This doesn't overflow because we're computing
|
|
|
|
|
// an address inside an alloca.
|
2017-02-15 04:56:18 +08:00
|
|
|
|
unsigned AlignedAlloc = MRI->createGenericVirtualRegister(PtrTy);
|
|
|
|
|
MIRBuilder.buildPtrMask(AlignedAlloc, AllocTmp, Log2_32(Align));
|
|
|
|
|
AllocTmp = AlignedAlloc;
|
2017-02-04 02:22:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-15 04:56:18 +08:00
|
|
|
|
MIRBuilder.buildCopy(SPReg, AllocTmp);
|
|
|
|
|
MIRBuilder.buildCopy(getOrCreateVReg(AI), AllocTmp);
|
2016-08-27 07:49:05 +08:00
|
|
|
|
|
2017-02-04 02:22:45 +08:00
|
|
|
|
MF->getFrameInfo().CreateVariableSizedObject(Align ? Align : 1, &AI);
|
|
|
|
|
assert(MF->getFrameInfo().hasVarSizedObjects());
|
2016-07-23 00:59:52 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-16 07:22:33 +08:00
|
|
|
|
bool IRTranslator::translateVAArg(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
// FIXME: We may need more info about the type. Because of how LLT works,
|
|
|
|
|
// we're completely discarding the i64/double distinction here (amongst
|
|
|
|
|
// others). Fortunately the ABIs I know of where that matters don't use va_arg
|
|
|
|
|
// anyway but that's not guaranteed.
|
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_VAARG)
|
|
|
|
|
.addDef(getOrCreateVReg(U))
|
|
|
|
|
.addUse(getOrCreateVReg(*U.getOperand(0)))
|
|
|
|
|
.addImm(DL->getABITypeAlignment(U.getType()));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-11 03:08:28 +08:00
|
|
|
|
bool IRTranslator::translateInsertElement(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
// If it is a <1 x Ty> vector, use the scalar as it is
|
|
|
|
|
// not a legal vector type in LLT.
|
|
|
|
|
if (U.getType()->getVectorNumElements() == 1) {
|
|
|
|
|
unsigned Elt = getOrCreateVReg(*U.getOperand(1));
|
2018-05-16 18:32:02 +08:00
|
|
|
|
auto &Regs = *VMap.getVRegs(U);
|
|
|
|
|
if (Regs.empty()) {
|
|
|
|
|
Regs.push_back(Elt);
|
|
|
|
|
VMap.getOffsets(U)->push_back(0);
|
|
|
|
|
} else {
|
|
|
|
|
MIRBuilder.buildCopy(Regs[0], Elt);
|
|
|
|
|
}
|
2017-03-11 03:08:28 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-05-16 18:32:02 +08:00
|
|
|
|
|
2017-04-19 14:38:37 +08:00
|
|
|
|
unsigned Res = getOrCreateVReg(U);
|
|
|
|
|
unsigned Val = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
|
unsigned Elt = getOrCreateVReg(*U.getOperand(1));
|
|
|
|
|
unsigned Idx = getOrCreateVReg(*U.getOperand(2));
|
|
|
|
|
MIRBuilder.buildInsertVectorElement(Res, Val, Elt, Idx);
|
2017-03-11 03:08:28 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IRTranslator::translateExtractElement(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
// If it is a <1 x Ty> vector, use the scalar as it is
|
|
|
|
|
// not a legal vector type in LLT.
|
|
|
|
|
if (U.getOperand(0)->getType()->getVectorNumElements() == 1) {
|
|
|
|
|
unsigned Elt = getOrCreateVReg(*U.getOperand(0));
|
2018-05-16 18:32:02 +08:00
|
|
|
|
auto &Regs = *VMap.getVRegs(U);
|
|
|
|
|
if (Regs.empty()) {
|
|
|
|
|
Regs.push_back(Elt);
|
|
|
|
|
VMap.getOffsets(U)->push_back(0);
|
|
|
|
|
} else {
|
|
|
|
|
MIRBuilder.buildCopy(Regs[0], Elt);
|
|
|
|
|
}
|
2017-03-11 03:08:28 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2017-04-19 14:38:37 +08:00
|
|
|
|
unsigned Res = getOrCreateVReg(U);
|
|
|
|
|
unsigned Val = getOrCreateVReg(*U.getOperand(0));
|
2018-10-25 22:04:54 +08:00
|
|
|
|
const auto &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
|
unsigned PreferredVecIdxWidth = TLI.getVectorIdxTy(*DL).getSizeInBits();
|
|
|
|
|
unsigned Idx = 0;
|
|
|
|
|
if (auto *CI = dyn_cast<ConstantInt>(U.getOperand(1))) {
|
|
|
|
|
if (CI->getBitWidth() != PreferredVecIdxWidth) {
|
|
|
|
|
APInt NewIdx = CI->getValue().sextOrTrunc(PreferredVecIdxWidth);
|
|
|
|
|
auto *NewIdxCI = ConstantInt::get(CI->getContext(), NewIdx);
|
|
|
|
|
Idx = getOrCreateVReg(*NewIdxCI);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!Idx)
|
|
|
|
|
Idx = getOrCreateVReg(*U.getOperand(1));
|
|
|
|
|
if (MRI->getType(Idx).getSizeInBits() != PreferredVecIdxWidth) {
|
|
|
|
|
const LLT &VecIdxTy = LLT::scalar(PreferredVecIdxWidth);
|
|
|
|
|
Idx = MIRBuilder.buildSExtOrTrunc(VecIdxTy, Idx)->getOperand(0).getReg();
|
|
|
|
|
}
|
2017-04-19 14:38:37 +08:00
|
|
|
|
MIRBuilder.buildExtractVectorElement(Res, Val, Idx);
|
2017-03-11 03:08:28 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-21 16:44:13 +08:00
|
|
|
|
bool IRTranslator::translateShuffleVector(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_SHUFFLE_VECTOR)
|
|
|
|
|
.addDef(getOrCreateVReg(U))
|
|
|
|
|
.addUse(getOrCreateVReg(*U.getOperand(0)))
|
|
|
|
|
.addUse(getOrCreateVReg(*U.getOperand(1)))
|
|
|
|
|
.addUse(getOrCreateVReg(*U.getOperand(2)));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translatePHI(const User &U, MachineIRBuilder &MIRBuilder) {
|
2016-08-11 07:02:41 +08:00
|
|
|
|
const PHINode &PI = cast<PHINode>(U);
|
2016-08-06 01:16:40 +08:00
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
SmallVector<MachineInstr *, 4> Insts;
|
|
|
|
|
for (auto Reg : getOrCreateVRegs(PI)) {
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
|
auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_PHI, {Reg}, {});
|
2018-05-16 18:32:02 +08:00
|
|
|
|
Insts.push_back(MIB.getInstr());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PendingPHIs.emplace_back(&PI, std::move(Insts));
|
2016-08-06 01:16:40 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
[globalisel][irtranslator] Add support for atomicrmw and (strong) cmpxchg
Summary:
This patch adds support for the atomicrmw instructions and the strong
cmpxchg instruction to the IRTranslator.
I've left out weak cmpxchg because LangRef.rst isn't entirely clear on what
difference it makes to the backend. As far as I can tell from the code, it
only matters to AtomicExpandPass which is run at the LLVM-IR level.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar, volkan, javed.absar
Reviewed By: qcolombet
Subscribers: kristof.beyls, javed.absar, igorb, llvm-commits
Differential Revision: https://reviews.llvm.org/D40092
llvm-svn: 336589
2018-07-10 03:33:40 +08:00
|
|
|
|
bool IRTranslator::translateAtomicCmpXchg(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
const AtomicCmpXchgInst &I = cast<AtomicCmpXchgInst>(U);
|
|
|
|
|
|
|
|
|
|
if (I.isWeak())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
auto Flags = I.isVolatile() ? MachineMemOperand::MOVolatile
|
|
|
|
|
: MachineMemOperand::MONone;
|
|
|
|
|
Flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore;
|
|
|
|
|
|
|
|
|
|
Type *ResType = I.getType();
|
|
|
|
|
Type *ValType = ResType->Type::getStructElementType(0);
|
|
|
|
|
|
|
|
|
|
auto Res = getOrCreateVRegs(I);
|
|
|
|
|
unsigned OldValRes = Res[0];
|
|
|
|
|
unsigned SuccessRes = Res[1];
|
|
|
|
|
unsigned Addr = getOrCreateVReg(*I.getPointerOperand());
|
|
|
|
|
unsigned Cmp = getOrCreateVReg(*I.getCompareOperand());
|
|
|
|
|
unsigned NewVal = getOrCreateVReg(*I.getNewValOperand());
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildAtomicCmpXchgWithSuccess(
|
|
|
|
|
OldValRes, SuccessRes, Addr, Cmp, NewVal,
|
|
|
|
|
*MF->getMachineMemOperand(MachinePointerInfo(I.getPointerOperand()),
|
|
|
|
|
Flags, DL->getTypeStoreSize(ValType),
|
|
|
|
|
getMemOpAlignment(I), AAMDNodes(), nullptr,
|
|
|
|
|
I.getSyncScopeID(), I.getSuccessOrdering(),
|
|
|
|
|
I.getFailureOrdering()));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IRTranslator::translateAtomicRMW(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
const AtomicRMWInst &I = cast<AtomicRMWInst>(U);
|
|
|
|
|
|
|
|
|
|
auto Flags = I.isVolatile() ? MachineMemOperand::MOVolatile
|
|
|
|
|
: MachineMemOperand::MONone;
|
|
|
|
|
Flags |= MachineMemOperand::MOLoad | MachineMemOperand::MOStore;
|
|
|
|
|
|
|
|
|
|
Type *ResType = I.getType();
|
|
|
|
|
|
|
|
|
|
unsigned Res = getOrCreateVReg(I);
|
|
|
|
|
unsigned Addr = getOrCreateVReg(*I.getPointerOperand());
|
|
|
|
|
unsigned Val = getOrCreateVReg(*I.getValOperand());
|
|
|
|
|
|
|
|
|
|
unsigned Opcode = 0;
|
|
|
|
|
switch (I.getOperation()) {
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unknown atomicrmw op");
|
|
|
|
|
return false;
|
|
|
|
|
case AtomicRMWInst::Xchg:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_XCHG;
|
|
|
|
|
break;
|
|
|
|
|
case AtomicRMWInst::Add:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_ADD;
|
|
|
|
|
break;
|
|
|
|
|
case AtomicRMWInst::Sub:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_SUB;
|
|
|
|
|
break;
|
|
|
|
|
case AtomicRMWInst::And:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_AND;
|
|
|
|
|
break;
|
|
|
|
|
case AtomicRMWInst::Nand:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_NAND;
|
|
|
|
|
break;
|
|
|
|
|
case AtomicRMWInst::Or:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_OR;
|
|
|
|
|
break;
|
|
|
|
|
case AtomicRMWInst::Xor:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_XOR;
|
|
|
|
|
break;
|
|
|
|
|
case AtomicRMWInst::Max:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_MAX;
|
|
|
|
|
break;
|
|
|
|
|
case AtomicRMWInst::Min:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_MIN;
|
|
|
|
|
break;
|
|
|
|
|
case AtomicRMWInst::UMax:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_UMAX;
|
|
|
|
|
break;
|
|
|
|
|
case AtomicRMWInst::UMin:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_UMIN;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildAtomicRMW(
|
|
|
|
|
Opcode, Res, Addr, Val,
|
|
|
|
|
*MF->getMachineMemOperand(MachinePointerInfo(I.getPointerOperand()),
|
|
|
|
|
Flags, DL->getTypeStoreSize(ResType),
|
|
|
|
|
getMemOpAlignment(I), AAMDNodes(), nullptr,
|
|
|
|
|
I.getSyncScopeID(), I.getOrdering()));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-06 01:16:40 +08:00
|
|
|
|
void IRTranslator::finishPendingPhis() {
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
#ifndef NDEBUG
|
2019-01-16 08:40:37 +08:00
|
|
|
|
DILocationVerifier Verifier;
|
|
|
|
|
GISelObserverWrapper WrapperObserver(&Verifier);
|
|
|
|
|
RAIIDelegateInstaller DelInstall(*MF, &WrapperObserver);
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
#endif // ifndef NDEBUG
|
2018-05-16 18:32:02 +08:00
|
|
|
|
for (auto &Phi : PendingPHIs) {
|
2016-08-06 01:16:40 +08:00
|
|
|
|
const PHINode *PI = Phi.first;
|
2018-05-16 18:32:02 +08:00
|
|
|
|
ArrayRef<MachineInstr *> ComponentPHIs = Phi.second;
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder->setDebugLoc(PI->getDebugLoc());
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
Verifier.setCurrentInst(PI);
|
|
|
|
|
#endif // ifndef NDEBUG
|
2016-08-06 01:16:40 +08:00
|
|
|
|
|
|
|
|
|
// All MachineBasicBlocks exist, add them to the PHI. We assume IRTranslator
|
|
|
|
|
// won't create extra control flow here, otherwise we need to find the
|
|
|
|
|
// dominating predecessor here (or perhaps force the weirder IRTranslators
|
|
|
|
|
// to provide a simple boundary).
|
2017-01-18 06:13:50 +08:00
|
|
|
|
SmallSet<const BasicBlock *, 4> HandledPreds;
|
|
|
|
|
|
2016-08-06 01:16:40 +08:00
|
|
|
|
for (unsigned i = 0; i < PI->getNumIncomingValues(); ++i) {
|
2017-01-18 06:13:50 +08:00
|
|
|
|
auto IRPred = PI->getIncomingBlock(i);
|
|
|
|
|
if (HandledPreds.count(IRPred))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
HandledPreds.insert(IRPred);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
ArrayRef<unsigned> ValRegs = getOrCreateVRegs(*PI->getIncomingValue(i));
|
2017-01-18 06:13:50 +08:00
|
|
|
|
for (auto Pred : getMachinePredBBs({IRPred, PI->getParent()})) {
|
2018-05-16 18:32:02 +08:00
|
|
|
|
assert(Pred->isSuccessor(ComponentPHIs[0]->getParent()) &&
|
2017-01-18 06:13:50 +08:00
|
|
|
|
"incorrect CFG at MachineBasicBlock level");
|
2018-05-16 18:32:02 +08:00
|
|
|
|
for (unsigned j = 0; j < ValRegs.size(); ++j) {
|
|
|
|
|
MachineInstrBuilder MIB(*MF, ComponentPHIs[j]);
|
|
|
|
|
MIB.addUse(ValRegs[j]);
|
|
|
|
|
MIB.addMBB(Pred);
|
|
|
|
|
}
|
2017-01-18 06:13:50 +08:00
|
|
|
|
}
|
2016-08-06 01:16:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
bool IRTranslator::valueIsSplit(const Value &V,
|
|
|
|
|
SmallVectorImpl<uint64_t> *Offsets) {
|
|
|
|
|
SmallVector<LLT, 4> SplitTys;
|
2018-08-14 20:04:25 +08:00
|
|
|
|
if (Offsets && !Offsets->empty())
|
|
|
|
|
Offsets->clear();
|
2018-05-16 18:32:02 +08:00
|
|
|
|
computeValueLLTs(*DL, *V.getType(), SplitTys, Offsets);
|
|
|
|
|
return SplitTys.size() > 1;
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-11 06:59:27 +08:00
|
|
|
|
bool IRTranslator::translate(const Instruction &Inst) {
|
2019-01-16 08:40:37 +08:00
|
|
|
|
CurBuilder->setDebugLoc(Inst.getDebugLoc());
|
|
|
|
|
EntryBuilder->setDebugLoc(Inst.getDebugLoc());
|
2016-02-11 06:59:27 +08:00
|
|
|
|
switch(Inst.getOpcode()) {
|
2019-01-16 08:40:37 +08:00
|
|
|
|
#define HANDLE_INST(NUM, OPCODE, CLASS) \
|
|
|
|
|
case Instruction::OPCODE: \
|
|
|
|
|
return translate##OPCODE(Inst, *CurBuilder.get());
|
2016-08-11 07:02:41 +08:00
|
|
|
|
#include "llvm/IR/Instruction.def"
|
2016-02-12 02:53:28 +08:00
|
|
|
|
default:
|
2017-03-11 08:28:33 +08:00
|
|
|
|
return false;
|
2016-02-11 06:59:27 +08:00
|
|
|
|
}
|
2016-01-21 04:58:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-10 05:28:04 +08:00
|
|
|
|
bool IRTranslator::translate(const Constant &C, unsigned Reg) {
|
2016-08-10 07:01:30 +08:00
|
|
|
|
if (auto CI = dyn_cast<ConstantInt>(&C))
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder->buildConstant(Reg, *CI);
|
2016-08-20 04:09:15 +08:00
|
|
|
|
else if (auto CF = dyn_cast<ConstantFP>(&C))
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder->buildFConstant(Reg, *CF);
|
2016-08-10 07:01:30 +08:00
|
|
|
|
else if (isa<UndefValue>(C))
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder->buildUndef(Reg);
|
2018-03-23 01:31:38 +08:00
|
|
|
|
else if (isa<ConstantPointerNull>(C)) {
|
|
|
|
|
// As we are trying to build a constant val of 0 into a pointer,
|
|
|
|
|
// insert a cast to make them correct with respect to types.
|
|
|
|
|
unsigned NullSize = DL->getTypeSizeInBits(C.getType());
|
|
|
|
|
auto *ZeroTy = Type::getIntNTy(C.getContext(), NullSize);
|
|
|
|
|
auto *ZeroVal = ConstantInt::get(ZeroTy, 0);
|
|
|
|
|
unsigned ZeroReg = getOrCreateVReg(*ZeroVal);
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder->buildCast(Reg, ZeroReg);
|
2018-03-23 01:31:38 +08:00
|
|
|
|
} else if (auto GV = dyn_cast<GlobalValue>(&C))
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder->buildGlobalValue(Reg, GV);
|
2017-03-11 05:23:13 +08:00
|
|
|
|
else if (auto CAZ = dyn_cast<ConstantAggregateZero>(&C)) {
|
|
|
|
|
if (!CAZ->getType()->isVectorTy())
|
|
|
|
|
return false;
|
2017-03-15 07:45:06 +08:00
|
|
|
|
// Return the scalar if it is a <1 x Ty> vector.
|
|
|
|
|
if (CAZ->getNumElements() == 1)
|
|
|
|
|
return translate(*CAZ->getElementValue(0u), Reg);
|
2018-12-11 02:44:58 +08:00
|
|
|
|
SmallVector<unsigned, 4> Ops;
|
2017-03-11 05:23:13 +08:00
|
|
|
|
for (unsigned i = 0; i < CAZ->getNumElements(); ++i) {
|
|
|
|
|
Constant &Elt = *CAZ->getElementValue(i);
|
|
|
|
|
Ops.push_back(getOrCreateVReg(Elt));
|
|
|
|
|
}
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder->buildBuildVector(Reg, Ops);
|
GlobalISel: Translate ConstantDataVector
Reviewers: qcolombet, aditya_nandakumar, dsanders, t.p.northover, javed.absar, ab
Reviewed By: qcolombet, dsanders, ab
Subscribers: dberris, rovka, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30216
llvm-svn: 297670
2017-03-14 05:36:19 +08:00
|
|
|
|
} else if (auto CV = dyn_cast<ConstantDataVector>(&C)) {
|
2017-03-15 07:45:06 +08:00
|
|
|
|
// Return the scalar if it is a <1 x Ty> vector.
|
|
|
|
|
if (CV->getNumElements() == 1)
|
|
|
|
|
return translate(*CV->getElementAsConstant(0), Reg);
|
2018-12-11 02:44:58 +08:00
|
|
|
|
SmallVector<unsigned, 4> Ops;
|
GlobalISel: Translate ConstantDataVector
Reviewers: qcolombet, aditya_nandakumar, dsanders, t.p.northover, javed.absar, ab
Reviewed By: qcolombet, dsanders, ab
Subscribers: dberris, rovka, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D30216
llvm-svn: 297670
2017-03-14 05:36:19 +08:00
|
|
|
|
for (unsigned i = 0; i < CV->getNumElements(); ++i) {
|
|
|
|
|
Constant &Elt = *CV->getElementAsConstant(i);
|
|
|
|
|
Ops.push_back(getOrCreateVReg(Elt));
|
|
|
|
|
}
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder->buildBuildVector(Reg, Ops);
|
2017-03-11 05:23:13 +08:00
|
|
|
|
} else if (auto CE = dyn_cast<ConstantExpr>(&C)) {
|
2016-08-11 07:02:41 +08:00
|
|
|
|
switch(CE->getOpcode()) {
|
2019-01-16 08:40:37 +08:00
|
|
|
|
#define HANDLE_INST(NUM, OPCODE, CLASS) \
|
|
|
|
|
case Instruction::OPCODE: \
|
|
|
|
|
return translate##OPCODE(*CE, *EntryBuilder.get());
|
2016-08-11 07:02:41 +08:00
|
|
|
|
#include "llvm/IR/Instruction.def"
|
|
|
|
|
default:
|
2017-03-11 08:28:33 +08:00
|
|
|
|
return false;
|
2016-08-11 07:02:41 +08:00
|
|
|
|
}
|
2017-05-05 05:43:12 +08:00
|
|
|
|
} else if (auto CV = dyn_cast<ConstantVector>(&C)) {
|
|
|
|
|
if (CV->getNumOperands() == 1)
|
|
|
|
|
return translate(*CV->getOperand(0), Reg);
|
|
|
|
|
SmallVector<unsigned, 4> Ops;
|
|
|
|
|
for (unsigned i = 0; i < CV->getNumOperands(); ++i) {
|
|
|
|
|
Ops.push_back(getOrCreateVReg(*CV->getOperand(i)));
|
|
|
|
|
}
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder->buildBuildVector(Reg, Ops);
|
2018-07-31 08:08:50 +08:00
|
|
|
|
} else if (auto *BA = dyn_cast<BlockAddress>(&C)) {
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder->buildBlockAddress(Reg, BA);
|
2017-03-11 08:28:33 +08:00
|
|
|
|
} else
|
2016-08-27 07:49:05 +08:00
|
|
|
|
return false;
|
2016-08-10 05:28:04 +08:00
|
|
|
|
|
2016-08-10 07:01:30 +08:00
|
|
|
|
return true;
|
2016-08-10 05:28:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-12 00:21:29 +08:00
|
|
|
|
void IRTranslator::finalizeFunction() {
|
2016-02-11 06:59:27 +08:00
|
|
|
|
// Release the memory used by the different maps we
|
|
|
|
|
// needed during the translation.
|
2016-12-06 07:10:19 +08:00
|
|
|
|
PendingPHIs.clear();
|
2018-05-16 18:32:02 +08:00
|
|
|
|
VMap.reset();
|
2016-11-01 02:30:59 +08:00
|
|
|
|
FrameIndices.clear();
|
2017-01-18 06:13:50 +08:00
|
|
|
|
MachinePreds.clear();
|
2017-05-18 01:41:55 +08:00
|
|
|
|
// MachineIRBuilder::DebugLoc can outlive the DILocation it holds. Clear it
|
|
|
|
|
// to avoid accessing free’d memory (in runOnMachineFunction) and to avoid
|
|
|
|
|
// destroying it twice (in ~IRTranslator() and ~LLVMContext())
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder.reset();
|
|
|
|
|
CurBuilder.reset();
|
2016-01-21 04:58:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:17:47 +08:00
|
|
|
|
bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {
|
|
|
|
|
MF = &CurMF;
|
2017-12-16 06:22:58 +08:00
|
|
|
|
const Function &F = MF->getFunction();
|
2016-02-12 03:59:41 +08:00
|
|
|
|
if (F.empty())
|
|
|
|
|
return false;
|
2019-01-16 08:40:37 +08:00
|
|
|
|
GISelCSEAnalysisWrapper &Wrapper =
|
|
|
|
|
getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEWrapper();
|
|
|
|
|
// Set the CSEConfig and run the analysis.
|
|
|
|
|
GISelCSEInfo *CSEInfo = nullptr;
|
|
|
|
|
TPC = &getAnalysis<TargetPassConfig>();
|
2019-01-25 07:11:25 +08:00
|
|
|
|
bool EnableCSE = EnableCSEInIRTranslator.getNumOccurrences()
|
|
|
|
|
? EnableCSEInIRTranslator
|
|
|
|
|
: TPC->isGISelCSEEnabled();
|
|
|
|
|
|
2019-01-16 08:40:37 +08:00
|
|
|
|
if (EnableCSE) {
|
|
|
|
|
EntryBuilder = make_unique<CSEMIRBuilder>(CurMF);
|
|
|
|
|
std::unique_ptr<CSEConfig> Config = make_unique<CSEConfig>();
|
|
|
|
|
CSEInfo = &Wrapper.get(std::move(Config));
|
|
|
|
|
EntryBuilder->setCSEInfo(CSEInfo);
|
|
|
|
|
CurBuilder = make_unique<CSEMIRBuilder>(CurMF);
|
|
|
|
|
CurBuilder->setCSEInfo(CSEInfo);
|
|
|
|
|
} else {
|
|
|
|
|
EntryBuilder = make_unique<MachineIRBuilder>();
|
|
|
|
|
CurBuilder = make_unique<MachineIRBuilder>();
|
|
|
|
|
}
|
2016-12-08 05:17:47 +08:00
|
|
|
|
CLI = MF->getSubtarget().getCallLowering();
|
2019-01-16 08:40:37 +08:00
|
|
|
|
CurBuilder->setMF(*MF);
|
|
|
|
|
EntryBuilder->setMF(*MF);
|
2016-12-08 05:17:47 +08:00
|
|
|
|
MRI = &MF->getRegInfo();
|
2016-07-23 00:59:52 +08:00
|
|
|
|
DL = &F.getParent()->getDataLayout();
|
2017-06-27 06:44:03 +08:00
|
|
|
|
ORE = llvm::make_unique<OptimizationRemarkEmitter>(&F);
|
2016-07-23 00:59:52 +08:00
|
|
|
|
|
2016-08-06 01:50:36 +08:00
|
|
|
|
assert(PendingPHIs.empty() && "stale PHIs");
|
|
|
|
|
|
2017-12-12 00:58:29 +08:00
|
|
|
|
if (!DL->isLittleEndian()) {
|
|
|
|
|
// Currently we don't properly handle big endian code.
|
|
|
|
|
OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",
|
2017-12-16 06:22:58 +08:00
|
|
|
|
F.getSubprogram(), &F.getEntryBlock());
|
2017-12-12 00:58:29 +08:00
|
|
|
|
R << "unable to translate in big endian mode";
|
|
|
|
|
reportTranslationError(*MF, *TPC, *ORE, R);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-24 07:57:28 +08:00
|
|
|
|
// Release the per-function state when we return, whether we succeeded or not.
|
|
|
|
|
auto FinalizeOnReturn = make_scope_exit([this]() { finalizeFunction(); });
|
|
|
|
|
|
2017-03-16 02:22:33 +08:00
|
|
|
|
// Setup a separate basic-block for the arguments and constants
|
2016-12-08 05:17:47 +08:00
|
|
|
|
MachineBasicBlock *EntryBB = MF->CreateMachineBasicBlock();
|
|
|
|
|
MF->push_back(EntryBB);
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder->setMBB(*EntryBB);
|
2016-12-08 05:05:38 +08:00
|
|
|
|
|
2017-03-16 02:22:33 +08:00
|
|
|
|
// Create all blocks, in IR order, to preserve the layout.
|
|
|
|
|
for (const BasicBlock &BB: F) {
|
|
|
|
|
auto *&MBB = BBToMBB[&BB];
|
|
|
|
|
|
|
|
|
|
MBB = MF->CreateMachineBasicBlock(&BB);
|
|
|
|
|
MF->push_back(MBB);
|
|
|
|
|
|
|
|
|
|
if (BB.hasAddressTaken())
|
|
|
|
|
MBB->setHasAddressTaken();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make our arguments/constants entry block fallthrough to the IR entry block.
|
|
|
|
|
EntryBB->addSuccessor(&getMBB(F.front()));
|
|
|
|
|
|
2016-12-08 05:05:38 +08:00
|
|
|
|
// Lower the actual args into this basic block.
|
2016-02-12 03:59:41 +08:00
|
|
|
|
SmallVector<unsigned, 8> VRegArgs;
|
2017-12-01 04:06:02 +08:00
|
|
|
|
for (const Argument &Arg: F.args()) {
|
|
|
|
|
if (DL->getTypeStoreSize(Arg.getType()) == 0)
|
|
|
|
|
continue; // Don't handle zero sized types.
|
2018-05-16 18:32:02 +08:00
|
|
|
|
VRegArgs.push_back(
|
|
|
|
|
MRI->createGenericVirtualRegister(getLLTForType(*Arg.getType(), *DL)));
|
2017-12-01 04:06:02 +08:00
|
|
|
|
}
|
2018-05-16 18:32:02 +08:00
|
|
|
|
|
2018-07-26 09:25:58 +08:00
|
|
|
|
// We don't currently support translating swifterror or swiftself functions.
|
|
|
|
|
for (auto &Arg : F.args()) {
|
|
|
|
|
if (Arg.hasSwiftErrorAttr() || Arg.hasSwiftSelfAttr()) {
|
|
|
|
|
OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",
|
|
|
|
|
F.getSubprogram(), &F.getEntryBlock());
|
|
|
|
|
R << "unable to lower arguments due to swifterror/swiftself: "
|
|
|
|
|
<< ore::NV("Prototype", F.getType());
|
|
|
|
|
reportTranslationError(*MF, *TPC, *ORE, R);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-16 08:40:37 +08:00
|
|
|
|
if (!CLI->lowerFormalArguments(*EntryBuilder.get(), F, VRegArgs)) {
|
2017-02-24 08:34:44 +08:00
|
|
|
|
OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",
|
2017-12-16 06:22:58 +08:00
|
|
|
|
F.getSubprogram(), &F.getEntryBlock());
|
2017-02-24 05:05:42 +08:00
|
|
|
|
R << "unable to lower arguments: " << ore::NV("Prototype", F.getType());
|
|
|
|
|
reportTranslationError(*MF, *TPC, *ORE, R);
|
|
|
|
|
return false;
|
2016-08-27 07:49:05 +08:00
|
|
|
|
}
|
2016-02-12 03:59:41 +08:00
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
auto ArgIt = F.arg_begin();
|
|
|
|
|
for (auto &VArg : VRegArgs) {
|
|
|
|
|
// If the argument is an unsplit scalar then don't use unpackRegs to avoid
|
|
|
|
|
// creating redundant copies.
|
|
|
|
|
if (!valueIsSplit(*ArgIt, VMap.getOffsets(*ArgIt))) {
|
|
|
|
|
auto &VRegs = *VMap.getVRegs(cast<Value>(*ArgIt));
|
|
|
|
|
assert(VRegs.empty() && "VRegs already populated?");
|
|
|
|
|
VRegs.push_back(VArg);
|
|
|
|
|
} else {
|
2019-01-16 08:40:37 +08:00
|
|
|
|
unpackRegs(*ArgIt, VArg, *EntryBuilder.get());
|
2018-05-16 18:32:02 +08:00
|
|
|
|
}
|
|
|
|
|
ArgIt++;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-01 10:17:42 +08:00
|
|
|
|
// Need to visit defs before uses when translating instructions.
|
2019-01-16 08:40:37 +08:00
|
|
|
|
GISelObserverWrapper WrapperObserver;
|
|
|
|
|
if (EnableCSE && CSEInfo)
|
|
|
|
|
WrapperObserver.addObserver(CSEInfo);
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
{
|
|
|
|
|
ReversePostOrderTraversal<const Function *> RPOT(&F);
|
|
|
|
|
#ifndef NDEBUG
|
2019-01-16 08:40:37 +08:00
|
|
|
|
DILocationVerifier Verifier;
|
|
|
|
|
WrapperObserver.addObserver(&Verifier);
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
#endif // ifndef NDEBUG
|
2019-01-16 08:40:37 +08:00
|
|
|
|
RAIIDelegateInstaller DelInstall(*MF, &WrapperObserver);
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
for (const BasicBlock *BB : RPOT) {
|
|
|
|
|
MachineBasicBlock &MBB = getMBB(*BB);
|
|
|
|
|
// Set the insertion point of all the following translations to
|
|
|
|
|
// the end of this basic block.
|
2019-01-16 08:40:37 +08:00
|
|
|
|
CurBuilder->setMBB(MBB);
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
|
|
|
|
|
for (const Instruction &Inst : *BB) {
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
Verifier.setCurrentInst(&Inst);
|
|
|
|
|
#endif // ifndef NDEBUG
|
|
|
|
|
if (translate(Inst))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",
|
|
|
|
|
Inst.getDebugLoc(), BB);
|
|
|
|
|
R << "unable to translate instruction: " << ore::NV("Opcode", &Inst);
|
|
|
|
|
|
|
|
|
|
if (ORE->allowExtraAnalysis("gisel-irtranslator")) {
|
|
|
|
|
std::string InstStrStorage;
|
|
|
|
|
raw_string_ostream InstStr(InstStrStorage);
|
|
|
|
|
InstStr << Inst;
|
|
|
|
|
|
|
|
|
|
R << ": '" << InstStr.str() << "'";
|
|
|
|
|
}
|
2017-09-19 02:50:09 +08:00
|
|
|
|
|
[globalisel][irtranslator] Verify that DILocations aren't lost in translation
Summary:
Also fix a couple bugs where DILocations are lost. EntryBuilder wasn't passing
on debug locations for PHI's, constants, GLOBAL_VALUE, etc.
Reviewers: aprantl, vsk, bogner, aditya_nandakumar, volkan, rtereshin, aemerson
Reviewed By: aemerson
Subscribers: aemerson, rovka, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D53740
llvm-svn: 345743
2018-11-01 01:31:23 +08:00
|
|
|
|
reportTranslationError(*MF, *TPC, *ORE, R);
|
|
|
|
|
return false;
|
2017-09-19 02:50:09 +08:00
|
|
|
|
}
|
2016-02-11 06:59:27 +08:00
|
|
|
|
}
|
2019-01-16 08:40:37 +08:00
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
WrapperObserver.removeObserver(&Verifier);
|
|
|
|
|
#endif
|
2016-02-11 06:59:27 +08:00
|
|
|
|
}
|
2016-07-13 06:23:42 +08:00
|
|
|
|
|
2017-02-24 07:57:36 +08:00
|
|
|
|
finishPendingPhis();
|
|
|
|
|
|
|
|
|
|
// Merge the argument lowering and constants block with its single
|
|
|
|
|
// successor, the LLVM-IR entry block. We want the basic block to
|
|
|
|
|
// be maximal.
|
|
|
|
|
assert(EntryBB->succ_size() == 1 &&
|
|
|
|
|
"Custom BB used for lowering should have only one successor");
|
|
|
|
|
// Get the successor of the current entry block.
|
|
|
|
|
MachineBasicBlock &NewEntryBB = **EntryBB->succ_begin();
|
|
|
|
|
assert(NewEntryBB.pred_size() == 1 &&
|
|
|
|
|
"LLVM-IR entry block has a predecessor!?");
|
|
|
|
|
// Move all the instruction from the current entry block to the
|
|
|
|
|
// new entry block.
|
|
|
|
|
NewEntryBB.splice(NewEntryBB.begin(), EntryBB, EntryBB->begin(),
|
|
|
|
|
EntryBB->end());
|
|
|
|
|
|
|
|
|
|
// Update the live-in information for the new entry block.
|
|
|
|
|
for (const MachineBasicBlock::RegisterMaskPair &LiveIn : EntryBB->liveins())
|
|
|
|
|
NewEntryBB.addLiveIn(LiveIn);
|
|
|
|
|
NewEntryBB.sortUniqueLiveIns();
|
|
|
|
|
|
|
|
|
|
// Get rid of the now empty basic block.
|
|
|
|
|
EntryBB->removeSuccessor(&NewEntryBB);
|
|
|
|
|
MF->remove(EntryBB);
|
|
|
|
|
MF->DeleteMachineBasicBlock(EntryBB);
|
|
|
|
|
|
|
|
|
|
assert(&MF->front() == &NewEntryBB &&
|
|
|
|
|
"New entry wasn't next in the list of basic block!");
|
2016-08-06 01:16:40 +08:00
|
|
|
|
|
2018-07-13 08:08:38 +08:00
|
|
|
|
// Initialize stack protector information.
|
|
|
|
|
StackProtector &SP = getAnalysis<StackProtector>();
|
|
|
|
|
SP.copyToMachineFrameInfo(MF->getFrameInfo());
|
|
|
|
|
|
2016-01-21 04:58:56 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|