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"
|
2019-06-22 02:10:38 +08:00
|
|
|
|
#include "llvm/Analysis/BranchProbabilityInfo.h"
|
2020-01-13 03:10:42 +08:00
|
|
|
|
#include "llvm/Analysis/Loads.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"
|
[GlobalISel] Introduce InlineAsmLowering class
Summary:
Similar to the CallLowering class used for lowering LLVM IR calls to MIR calls,
we introduce a separate class for lowering LLVM IR inline asm to MIR INLINEASM.
There is no functional change yet, all existing tests should pass.
Reviewers: arsenm, dsanders, aemerson, volkan, t.p.northover, paquette
Reviewed By: aemerson
Subscribers: gargaroff, wdng, mgorny, rovka, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78316
2020-04-08 20:40:43 +08:00
|
|
|
|
#include "llvm/CodeGen/GlobalISel/InlineAsmLowering.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"
|
2020-07-29 21:48:26 +08:00
|
|
|
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#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"
|
2020-08-25 05:10:38 +08:00
|
|
|
|
#include "llvm/CodeGen/SwitchLoweringUtils.h"
|
2017-11-17 09:07:10 +08:00
|
|
|
|
#include "llvm/CodeGen/TargetFrameLowering.h"
|
2019-09-11 07:34:45 +08:00
|
|
|
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
2017-11-17 09:07:10 +08:00
|
|
|
|
#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"
|
2020-08-25 05:10:38 +08:00
|
|
|
|
#include "llvm/IR/InstrTypes.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#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"
|
2020-08-25 05:10:38 +08:00
|
|
|
|
#include "llvm/IR/PatternMatch.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"
|
Sink all InitializePasses.h includes
This file lists every pass in LLVM, and is included by Pass.h, which is
very popular. Every time we add, remove, or rename a pass in LLVM, it
caused lots of recompilation.
I found this fact by looking at this table, which is sorted by the
number of times a file was changed over the last 100,000 git commits
multiplied by the number of object files that depend on it in the
current checkout:
recompiles touches affected_files header
342380 95 3604 llvm/include/llvm/ADT/STLExtras.h
314730 234 1345 llvm/include/llvm/InitializePasses.h
307036 118 2602 llvm/include/llvm/ADT/APInt.h
213049 59 3611 llvm/include/llvm/Support/MathExtras.h
170422 47 3626 llvm/include/llvm/Support/Compiler.h
162225 45 3605 llvm/include/llvm/ADT/Optional.h
158319 63 2513 llvm/include/llvm/ADT/Triple.h
140322 39 3598 llvm/include/llvm/ADT/StringRef.h
137647 59 2333 llvm/include/llvm/Support/Error.h
131619 73 1803 llvm/include/llvm/Support/FileSystem.h
Before this change, touching InitializePasses.h would cause 1345 files
to recompile. After this change, touching it only causes 550 compiles in
an incremental rebuild.
Reviewers: bkramer, asbirlea, bollu, jdoerfert
Differential Revision: https://reviews.llvm.org/D70211
2019-11-14 05:15:01 +08:00
|
|
|
|
#include "llvm/InitializePasses.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"
|
2021-05-25 00:49:32 +08:00
|
|
|
|
#include "llvm/Transforms/Utils/MemoryOpRemark.h"
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <cassert>
|
2020-08-29 07:21:34 +08:00
|
|
|
|
#include <cstddef>
|
2017-06-27 06:44:03 +08:00
|
|
|
|
#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)
|
2020-10-09 04:54:24 +08:00
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass)
|
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(StackProtector)
|
2021-05-25 00:49:32 +08:00
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
|
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
|
|
|
|
}
|
|
|
|
|
|
2020-08-29 07:21:34 +08:00
|
|
|
|
IRTranslator::IRTranslator(CodeGenOpt::Level optlevel)
|
|
|
|
|
: MachineFunctionPass(ID), OptLevel(optlevel) {}
|
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
|
2019-06-14 06:15:35 +08:00
|
|
|
|
// We allow insts in the entry block to have a debug loc line of 0 because
|
|
|
|
|
// they could have originated from constants, and we don't want a jumpy
|
|
|
|
|
// debug experience.
|
|
|
|
|
assert((CurrInst->getDebugLoc() == MI.getDebugLoc() ||
|
|
|
|
|
MI.getDebugLoc().getLine() == 0) &&
|
[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
|
|
|
|
"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>();
|
2020-08-29 07:21:34 +08:00
|
|
|
|
if (OptLevel != CodeGenOpt::None)
|
|
|
|
|
AU.addRequired<BranchProbabilityInfoWrapperPass>();
|
2021-05-25 00:49:32 +08:00
|
|
|
|
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
|
|
|
|
AU.addPreserved<TargetLibraryInfoWrapperPass>();
|
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
|
|
|
|
IRTranslator::ValueToVRegInfo::VRegListT &
|
|
|
|
|
IRTranslator::allocateVRegs(const Value &Val) {
|
2020-12-13 06:57:36 +08:00
|
|
|
|
auto VRegsIt = VMap.findVRegs(Val);
|
|
|
|
|
if (VRegsIt != VMap.vregs_end())
|
|
|
|
|
return *VRegsIt->second;
|
2018-05-16 18:32:02 +08:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-24 23:50:29 +08:00
|
|
|
|
ArrayRef<Register> IRTranslator::getOrCreateVRegs(const Value &Val) {
|
2018-05-16 18:32:02 +08:00
|
|
|
|
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) {
|
2020-07-29 21:42:03 +08:00
|
|
|
|
auto MapEntry = FrameIndices.find(&AI);
|
|
|
|
|
if (MapEntry != FrameIndices.end())
|
|
|
|
|
return MapEntry->second;
|
2016-11-01 02:30:59 +08:00
|
|
|
|
|
[AArch64] Fix issues with large arrays on stack
Summary:
This patch fixes a few issues when large arrays are allocated on the
stack. Currently, clang has inconsistent behaviour, for debug builds
there is an assertion failure when the array size on stack is around 2GB
but there is no assertion when the stack is around 8GB. For release
builds there is no assertion, the compilation succeeds but generates
incorrect code. The incorrect code generated is due to using
int/unsigned int instead of their 64-bit counterparts. This patch,
1) Removes the assertion in frame legality check.
2) Converts int/unsigned int in some places to the 64-bit variants. This
helps in generating correct code and removes the inconsistent behaviour.
3) Adds a test which runs without optimisations.
Reviewers: sdesmalen, efriedma, fhahn, aemerson
Reviewed By: efriedma
Subscribers: eli.friedman, fpetrogalli, kristof.beyls, hiraditya,
llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70496
2019-11-20 20:45:26 +08:00
|
|
|
|
uint64_t ElementSize = DL->getTypeAllocSize(AI.getAllocatedType());
|
|
|
|
|
uint64_t Size =
|
2016-11-01 02:30:59 +08:00
|
|
|
|
ElementSize * cast<ConstantInt>(AI.getArraySize())->getZExtValue();
|
|
|
|
|
|
|
|
|
|
// Always allocate at least one byte.
|
[AArch64] Fix issues with large arrays on stack
Summary:
This patch fixes a few issues when large arrays are allocated on the
stack. Currently, clang has inconsistent behaviour, for debug builds
there is an assertion failure when the array size on stack is around 2GB
but there is no assertion when the stack is around 8GB. For release
builds there is no assertion, the compilation succeeds but generates
incorrect code. The incorrect code generated is due to using
int/unsigned int instead of their 64-bit counterparts. This patch,
1) Removes the assertion in frame legality check.
2) Converts int/unsigned int in some places to the 64-bit variants. This
helps in generating correct code and removes the inconsistent behaviour.
3) Adds a test which runs without optimisations.
Reviewers: sdesmalen, efriedma, fhahn, aemerson
Reviewed By: efriedma
Subscribers: eli.friedman, fpetrogalli, kristof.beyls, hiraditya,
llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70496
2019-11-20 20:45:26 +08:00
|
|
|
|
Size = std::max<uint64_t>(Size, 1u);
|
2016-11-01 02:30:59 +08:00
|
|
|
|
|
|
|
|
|
int &FI = FrameIndices[&AI];
|
2020-07-01 15:28:11 +08:00
|
|
|
|
FI = MF->getFrameInfo().CreateStackObject(Size, AI.getAlign(), false, &AI);
|
2016-11-01 02:30:59 +08:00
|
|
|
|
return FI;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-31 02:50:49 +08:00
|
|
|
|
Align IRTranslator::getMemOpAlign(const Instruction &I) {
|
2020-05-15 05:48:10 +08:00
|
|
|
|
if (const StoreInst *SI = dyn_cast<StoreInst>(&I))
|
|
|
|
|
return SI->getAlign();
|
2021-02-23 04:36:20 +08:00
|
|
|
|
if (const LoadInst *LI = dyn_cast<LoadInst>(&I))
|
2020-05-18 04:14:42 +08:00
|
|
|
|
return LI->getAlign();
|
2021-02-23 04:36:20 +08:00
|
|
|
|
if (const AtomicCmpXchgInst *AI = dyn_cast<AtomicCmpXchgInst>(&I))
|
|
|
|
|
return AI->getAlign();
|
|
|
|
|
if (const AtomicRMWInst *AI = dyn_cast<AtomicRMWInst>(&I))
|
|
|
|
|
return AI->getAlign();
|
|
|
|
|
|
2020-03-31 02:50:49 +08:00
|
|
|
|
OptimizationRemarkMissed R("gisel-irtranslator", "", &I);
|
|
|
|
|
R << "unable to translate memop: " << ore::NV("Opcode", &I);
|
|
|
|
|
reportTranslationError(*MF, *TPC, *ORE, R);
|
|
|
|
|
return Align(1);
|
2016-07-27 04:23:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
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-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.
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Op0 = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
|
Register Op1 = getOrCreateVReg(*U.getOperand(1));
|
|
|
|
|
Register 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
|
|
|
|
}
|
|
|
|
|
|
2020-08-11 17:50:58 +08:00
|
|
|
|
bool IRTranslator::translateUnaryOp(unsigned Opcode, const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Op0 = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
|
Register Res = getOrCreateVReg(U);
|
2019-06-18 07:19:40 +08:00
|
|
|
|
uint16_t Flags = 0;
|
|
|
|
|
if (isa<Instruction>(U)) {
|
|
|
|
|
const Instruction &I = cast<Instruction>(U);
|
|
|
|
|
Flags = MachineInstr::copyFlagsFromInstruction(I);
|
|
|
|
|
}
|
2020-08-11 17:50:58 +08:00
|
|
|
|
MIRBuilder.buildInstr(Opcode, {Res}, {Op0}, Flags);
|
2018-11-14 02:15:47 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-11 17:50:58 +08:00
|
|
|
|
bool IRTranslator::translateFNeg(const User &U, MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
return translateUnaryOp(TargetOpcode::G_FNEG, U, MIRBuilder);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateCompare(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2019-10-13 19:29:35 +08:00
|
|
|
|
auto *CI = dyn_cast<CmpInst>(&U);
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Op0 = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
|
Register Op1 = getOrCreateVReg(*U.getOperand(1));
|
|
|
|
|
Register Res = getOrCreateVReg(U);
|
2016-08-20 04:48:16 +08:00
|
|
|
|
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(
|
2019-10-13 19:29:35 +08:00
|
|
|
|
Res, getOrCreateVReg(*Constant::getNullValue(U.getType())));
|
2017-03-16 03:21:11 +08:00
|
|
|
|
else if (Pred == CmpInst::FCMP_TRUE)
|
|
|
|
|
MIRBuilder.buildCopy(
|
2019-10-13 19:29:35 +08:00
|
|
|
|
Res, getOrCreateVReg(*Constant::getAllOnesValue(U.getType())));
|
2018-12-19 01:54:52 +08:00
|
|
|
|
else {
|
2019-10-13 19:29:35 +08:00
|
|
|
|
assert(CI && "Instruction should be CmpInst");
|
2020-01-16 20:09:48 +08:00
|
|
|
|
MIRBuilder.buildFCmp(Pred, Res, 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
|
|
|
|
|
2019-06-24 23:50:29 +08:00
|
|
|
|
ArrayRef<Register> VRegs;
|
2018-08-02 16:33:31 +08:00
|
|
|
|
if (Ret)
|
|
|
|
|
VRegs = getOrCreateVRegs(*Ret);
|
|
|
|
|
|
2019-06-24 23:50:29 +08:00
|
|
|
|
Register SwiftErrorVReg = 0;
|
2019-05-24 16:40:13 +08:00
|
|
|
|
if (CLI->supportSwiftError() && SwiftError.getFunctionArg()) {
|
|
|
|
|
SwiftErrorVReg = SwiftError.getOrCreateVRegUseAt(
|
|
|
|
|
&RI, &MIRBuilder.getMBB(), SwiftError.getFunctionArg());
|
|
|
|
|
}
|
|
|
|
|
|
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.
|
2020-12-23 14:52:36 +08:00
|
|
|
|
return CLI->lowerReturn(MIRBuilder, Ret, VRegs, FuncInfo, SwiftErrorVReg);
|
2016-02-12 02:53:28 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-08-25 05:10:38 +08:00
|
|
|
|
void IRTranslator::emitBranchForMergedCondition(
|
|
|
|
|
const Value *Cond, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
|
|
|
|
|
MachineBasicBlock *CurBB, MachineBasicBlock *SwitchBB,
|
|
|
|
|
BranchProbability TProb, BranchProbability FProb, bool InvertCond) {
|
|
|
|
|
// If the leaf of the tree is a comparison, merge the condition into
|
|
|
|
|
// the caseblock.
|
|
|
|
|
if (const CmpInst *BOp = dyn_cast<CmpInst>(Cond)) {
|
|
|
|
|
CmpInst::Predicate Condition;
|
|
|
|
|
if (const ICmpInst *IC = dyn_cast<ICmpInst>(Cond)) {
|
|
|
|
|
Condition = InvertCond ? IC->getInversePredicate() : IC->getPredicate();
|
|
|
|
|
} else {
|
|
|
|
|
const FCmpInst *FC = cast<FCmpInst>(Cond);
|
|
|
|
|
Condition = InvertCond ? FC->getInversePredicate() : FC->getPredicate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SwitchCG::CaseBlock CB(Condition, false, BOp->getOperand(0),
|
|
|
|
|
BOp->getOperand(1), nullptr, TBB, FBB, CurBB,
|
|
|
|
|
CurBuilder->getDebugLoc(), TProb, FProb);
|
|
|
|
|
SL->SwitchCases.push_back(CB);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create a CaseBlock record representing this branch.
|
|
|
|
|
CmpInst::Predicate Pred = InvertCond ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ;
|
|
|
|
|
SwitchCG::CaseBlock CB(
|
|
|
|
|
Pred, false, Cond, ConstantInt::getTrue(MF->getFunction().getContext()),
|
|
|
|
|
nullptr, TBB, FBB, CurBB, CurBuilder->getDebugLoc(), TProb, FProb);
|
|
|
|
|
SL->SwitchCases.push_back(CB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isValInBlock(const Value *V, const BasicBlock *BB) {
|
|
|
|
|
if (const Instruction *I = dyn_cast<Instruction>(V))
|
|
|
|
|
return I->getParent() == BB;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRTranslator::findMergedConditions(
|
|
|
|
|
const Value *Cond, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
|
|
|
|
|
MachineBasicBlock *CurBB, MachineBasicBlock *SwitchBB,
|
|
|
|
|
Instruction::BinaryOps Opc, BranchProbability TProb,
|
|
|
|
|
BranchProbability FProb, bool InvertCond) {
|
|
|
|
|
using namespace PatternMatch;
|
|
|
|
|
assert((Opc == Instruction::And || Opc == Instruction::Or) &&
|
|
|
|
|
"Expected Opc to be AND/OR");
|
|
|
|
|
// Skip over not part of the tree and remember to invert op and operands at
|
|
|
|
|
// next level.
|
|
|
|
|
Value *NotCond;
|
|
|
|
|
if (match(Cond, m_OneUse(m_Not(m_Value(NotCond)))) &&
|
|
|
|
|
isValInBlock(NotCond, CurBB->getBasicBlock())) {
|
|
|
|
|
findMergedConditions(NotCond, TBB, FBB, CurBB, SwitchBB, Opc, TProb, FProb,
|
|
|
|
|
!InvertCond);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Instruction *BOp = dyn_cast<Instruction>(Cond);
|
2021-01-01 03:46:10 +08:00
|
|
|
|
const Value *BOpOp0, *BOpOp1;
|
2020-08-25 05:10:38 +08:00
|
|
|
|
// Compute the effective opcode for Cond, taking into account whether it needs
|
|
|
|
|
// to be inverted, e.g.
|
|
|
|
|
// and (not (or A, B)), C
|
|
|
|
|
// gets lowered as
|
|
|
|
|
// and (and (not A, not B), C)
|
2021-01-01 03:46:10 +08:00
|
|
|
|
Instruction::BinaryOps BOpc = (Instruction::BinaryOps)0;
|
2020-08-25 05:10:38 +08:00
|
|
|
|
if (BOp) {
|
2021-01-01 03:46:10 +08:00
|
|
|
|
BOpc = match(BOp, m_LogicalAnd(m_Value(BOpOp0), m_Value(BOpOp1)))
|
|
|
|
|
? Instruction::And
|
|
|
|
|
: (match(BOp, m_LogicalOr(m_Value(BOpOp0), m_Value(BOpOp1)))
|
|
|
|
|
? Instruction::Or
|
|
|
|
|
: (Instruction::BinaryOps)0);
|
2020-08-25 05:10:38 +08:00
|
|
|
|
if (InvertCond) {
|
|
|
|
|
if (BOpc == Instruction::And)
|
|
|
|
|
BOpc = Instruction::Or;
|
|
|
|
|
else if (BOpc == Instruction::Or)
|
|
|
|
|
BOpc = Instruction::And;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If this node is not part of the or/and tree, emit it as a branch.
|
2021-01-01 03:46:10 +08:00
|
|
|
|
// Note that all nodes in the tree should have same opcode.
|
|
|
|
|
bool BOpIsInOrAndTree = BOpc && BOpc == Opc && BOp->hasOneUse();
|
|
|
|
|
if (!BOpIsInOrAndTree || BOp->getParent() != CurBB->getBasicBlock() ||
|
|
|
|
|
!isValInBlock(BOpOp0, CurBB->getBasicBlock()) ||
|
|
|
|
|
!isValInBlock(BOpOp1, CurBB->getBasicBlock())) {
|
2020-08-25 05:10:38 +08:00
|
|
|
|
emitBranchForMergedCondition(Cond, TBB, FBB, CurBB, SwitchBB, TProb, FProb,
|
|
|
|
|
InvertCond);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create TmpBB after CurBB.
|
|
|
|
|
MachineFunction::iterator BBI(CurBB);
|
|
|
|
|
MachineBasicBlock *TmpBB =
|
|
|
|
|
MF->CreateMachineBasicBlock(CurBB->getBasicBlock());
|
|
|
|
|
CurBB->getParent()->insert(++BBI, TmpBB);
|
|
|
|
|
|
|
|
|
|
if (Opc == Instruction::Or) {
|
|
|
|
|
// Codegen X | Y as:
|
|
|
|
|
// BB1:
|
|
|
|
|
// jmp_if_X TBB
|
|
|
|
|
// jmp TmpBB
|
|
|
|
|
// TmpBB:
|
|
|
|
|
// jmp_if_Y TBB
|
|
|
|
|
// jmp FBB
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
// We have flexibility in setting Prob for BB1 and Prob for TmpBB.
|
|
|
|
|
// The requirement is that
|
|
|
|
|
// TrueProb for BB1 + (FalseProb for BB1 * TrueProb for TmpBB)
|
|
|
|
|
// = TrueProb for original BB.
|
|
|
|
|
// Assuming the original probabilities are A and B, one choice is to set
|
|
|
|
|
// BB1's probabilities to A/2 and A/2+B, and set TmpBB's probabilities to
|
|
|
|
|
// A/(1+B) and 2B/(1+B). This choice assumes that
|
|
|
|
|
// TrueProb for BB1 == FalseProb for BB1 * TrueProb for TmpBB.
|
|
|
|
|
// Another choice is to assume TrueProb for BB1 equals to TrueProb for
|
|
|
|
|
// TmpBB, but the math is more complicated.
|
|
|
|
|
|
|
|
|
|
auto NewTrueProb = TProb / 2;
|
|
|
|
|
auto NewFalseProb = TProb / 2 + FProb;
|
|
|
|
|
// Emit the LHS condition.
|
2021-01-01 03:46:10 +08:00
|
|
|
|
findMergedConditions(BOpOp0, TBB, TmpBB, CurBB, SwitchBB, Opc, NewTrueProb,
|
|
|
|
|
NewFalseProb, InvertCond);
|
2020-08-25 05:10:38 +08:00
|
|
|
|
|
|
|
|
|
// Normalize A/2 and B to get A/(1+B) and 2B/(1+B).
|
|
|
|
|
SmallVector<BranchProbability, 2> Probs{TProb / 2, FProb};
|
|
|
|
|
BranchProbability::normalizeProbabilities(Probs.begin(), Probs.end());
|
|
|
|
|
// Emit the RHS condition into TmpBB.
|
2021-01-01 03:46:10 +08:00
|
|
|
|
findMergedConditions(BOpOp1, TBB, FBB, TmpBB, SwitchBB, Opc, Probs[0],
|
|
|
|
|
Probs[1], InvertCond);
|
2020-08-25 05:10:38 +08:00
|
|
|
|
} else {
|
|
|
|
|
assert(Opc == Instruction::And && "Unknown merge op!");
|
|
|
|
|
// Codegen X & Y as:
|
|
|
|
|
// BB1:
|
|
|
|
|
// jmp_if_X TmpBB
|
|
|
|
|
// jmp FBB
|
|
|
|
|
// TmpBB:
|
|
|
|
|
// jmp_if_Y TBB
|
|
|
|
|
// jmp FBB
|
|
|
|
|
//
|
|
|
|
|
// This requires creation of TmpBB after CurBB.
|
|
|
|
|
|
|
|
|
|
// We have flexibility in setting Prob for BB1 and Prob for TmpBB.
|
|
|
|
|
// The requirement is that
|
|
|
|
|
// FalseProb for BB1 + (TrueProb for BB1 * FalseProb for TmpBB)
|
|
|
|
|
// = FalseProb for original BB.
|
|
|
|
|
// Assuming the original probabilities are A and B, one choice is to set
|
|
|
|
|
// BB1's probabilities to A+B/2 and B/2, and set TmpBB's probabilities to
|
|
|
|
|
// 2A/(1+A) and B/(1+A). This choice assumes that FalseProb for BB1 ==
|
|
|
|
|
// TrueProb for BB1 * FalseProb for TmpBB.
|
|
|
|
|
|
|
|
|
|
auto NewTrueProb = TProb + FProb / 2;
|
|
|
|
|
auto NewFalseProb = FProb / 2;
|
|
|
|
|
// Emit the LHS condition.
|
2021-01-01 03:46:10 +08:00
|
|
|
|
findMergedConditions(BOpOp0, TmpBB, FBB, CurBB, SwitchBB, Opc, NewTrueProb,
|
|
|
|
|
NewFalseProb, InvertCond);
|
2020-08-25 05:10:38 +08:00
|
|
|
|
|
|
|
|
|
// Normalize A and B/2 to get 2A/(1+A) and B/(1+A).
|
|
|
|
|
SmallVector<BranchProbability, 2> Probs{TProb, FProb / 2};
|
|
|
|
|
BranchProbability::normalizeProbabilities(Probs.begin(), Probs.end());
|
|
|
|
|
// Emit the RHS condition into TmpBB.
|
2021-01-01 03:46:10 +08:00
|
|
|
|
findMergedConditions(BOpOp1, TBB, FBB, TmpBB, SwitchBB, Opc, Probs[0],
|
|
|
|
|
Probs[1], InvertCond);
|
2020-08-25 05:10:38 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IRTranslator::shouldEmitAsBranches(
|
|
|
|
|
const std::vector<SwitchCG::CaseBlock> &Cases) {
|
|
|
|
|
// For multiple cases, it's better to emit as branches.
|
|
|
|
|
if (Cases.size() != 2)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// If this is two comparisons of the same values or'd or and'd together, they
|
|
|
|
|
// will get folded into a single comparison, so don't emit two blocks.
|
|
|
|
|
if ((Cases[0].CmpLHS == Cases[1].CmpLHS &&
|
|
|
|
|
Cases[0].CmpRHS == Cases[1].CmpRHS) ||
|
|
|
|
|
(Cases[0].CmpRHS == Cases[1].CmpLHS &&
|
|
|
|
|
Cases[0].CmpLHS == Cases[1].CmpRHS)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Handle: (X != null) | (Y != null) --> (X|Y) != 0
|
|
|
|
|
// Handle: (X == null) & (Y == null) --> (X|Y) == 0
|
|
|
|
|
if (Cases[0].CmpRHS == Cases[1].CmpRHS &&
|
|
|
|
|
Cases[0].PredInfo.Pred == Cases[1].PredInfo.Pred &&
|
|
|
|
|
isa<Constant>(Cases[0].CmpRHS) &&
|
|
|
|
|
cast<Constant>(Cases[0].CmpRHS)->isNullValue()) {
|
|
|
|
|
if (Cases[0].PredInfo.Pred == CmpInst::ICMP_EQ &&
|
|
|
|
|
Cases[0].TrueBB == Cases[1].ThisBB)
|
|
|
|
|
return false;
|
|
|
|
|
if (Cases[0].PredInfo.Pred == CmpInst::ICMP_NE &&
|
|
|
|
|
Cases[0].FalseBB == Cases[1].ThisBB)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
2020-08-25 05:10:38 +08:00
|
|
|
|
auto &CurMBB = MIRBuilder.getMBB();
|
|
|
|
|
auto *Succ0MBB = &getMBB(*BrInst.getSuccessor(0));
|
|
|
|
|
|
|
|
|
|
if (BrInst.isUnconditional()) {
|
|
|
|
|
// If the unconditional target is the layout successor, fallthrough.
|
|
|
|
|
if (!CurMBB.isLayoutSuccessor(Succ0MBB))
|
|
|
|
|
MIRBuilder.buildBr(*Succ0MBB);
|
|
|
|
|
|
|
|
|
|
// Link successors.
|
|
|
|
|
for (const BasicBlock *Succ : successors(&BrInst))
|
|
|
|
|
CurMBB.addSuccessor(&getMBB(*Succ));
|
|
|
|
|
return true;
|
2016-03-12 01:28:03 +08:00
|
|
|
|
}
|
2016-07-30 01:58:00 +08:00
|
|
|
|
|
2020-08-25 05:10:38 +08:00
|
|
|
|
// If this condition is one of the special cases we handle, do special stuff
|
|
|
|
|
// now.
|
|
|
|
|
const Value *CondVal = BrInst.getCondition();
|
|
|
|
|
MachineBasicBlock *Succ1MBB = &getMBB(*BrInst.getSuccessor(1));
|
2017-03-22 07:42:50 +08:00
|
|
|
|
|
2020-08-25 05:10:38 +08:00
|
|
|
|
const auto &TLI = *MF->getSubtarget().getTargetLowering();
|
2016-07-30 01:58:00 +08:00
|
|
|
|
|
2020-08-25 05:10:38 +08:00
|
|
|
|
// If this is a series of conditions that are or'd or and'd together, emit
|
|
|
|
|
// this as a sequence of branches instead of setcc's with and/or operations.
|
|
|
|
|
// As long as jumps are not expensive (exceptions for multi-use logic ops,
|
|
|
|
|
// unpredictable branches, and vector extracts because those jumps are likely
|
|
|
|
|
// expensive for any target), this should improve performance.
|
|
|
|
|
// For example, instead of something like:
|
|
|
|
|
// cmp A, B
|
|
|
|
|
// C = seteq
|
|
|
|
|
// cmp D, E
|
|
|
|
|
// F = setle
|
|
|
|
|
// or C, F
|
|
|
|
|
// jnz foo
|
|
|
|
|
// Emit:
|
|
|
|
|
// cmp A, B
|
|
|
|
|
// je foo
|
|
|
|
|
// cmp D, E
|
|
|
|
|
// jle foo
|
|
|
|
|
using namespace PatternMatch;
|
2021-01-01 03:46:10 +08:00
|
|
|
|
const Instruction *CondI = dyn_cast<Instruction>(CondVal);
|
|
|
|
|
if (!TLI.isJumpExpensive() && CondI && CondI->hasOneUse() &&
|
|
|
|
|
!BrInst.hasMetadata(LLVMContext::MD_unpredictable)) {
|
|
|
|
|
Instruction::BinaryOps Opcode = (Instruction::BinaryOps)0;
|
|
|
|
|
Value *Vec;
|
|
|
|
|
const Value *BOp0, *BOp1;
|
|
|
|
|
if (match(CondI, m_LogicalAnd(m_Value(BOp0), m_Value(BOp1))))
|
|
|
|
|
Opcode = Instruction::And;
|
|
|
|
|
else if (match(CondI, m_LogicalOr(m_Value(BOp0), m_Value(BOp1))))
|
|
|
|
|
Opcode = Instruction::Or;
|
|
|
|
|
|
|
|
|
|
if (Opcode && !(match(BOp0, m_ExtractElt(m_Value(Vec), m_Value())) &&
|
|
|
|
|
match(BOp1, m_ExtractElt(m_Specific(Vec), m_Value())))) {
|
|
|
|
|
findMergedConditions(CondI, Succ0MBB, Succ1MBB, &CurMBB, &CurMBB, Opcode,
|
2020-08-25 05:10:38 +08:00
|
|
|
|
getEdgeProbability(&CurMBB, Succ0MBB),
|
|
|
|
|
getEdgeProbability(&CurMBB, Succ1MBB),
|
|
|
|
|
/*InvertCond=*/false);
|
|
|
|
|
assert(SL->SwitchCases[0].ThisBB == &CurMBB && "Unexpected lowering!");
|
|
|
|
|
|
|
|
|
|
// Allow some cases to be rejected.
|
|
|
|
|
if (shouldEmitAsBranches(SL->SwitchCases)) {
|
|
|
|
|
// Emit the branch for this block.
|
|
|
|
|
emitSwitchCase(SL->SwitchCases[0], &CurMBB, *CurBuilder);
|
|
|
|
|
SL->SwitchCases.erase(SL->SwitchCases.begin());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Okay, we decided not to do this, remove any inserted MBB's and clear
|
|
|
|
|
// SwitchCases.
|
|
|
|
|
for (unsigned I = 1, E = SL->SwitchCases.size(); I != E; ++I)
|
|
|
|
|
MF->erase(SL->SwitchCases[I].ThisBB);
|
|
|
|
|
|
|
|
|
|
SL->SwitchCases.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create a CaseBlock record representing this branch.
|
|
|
|
|
SwitchCG::CaseBlock CB(CmpInst::ICMP_EQ, false, CondVal,
|
|
|
|
|
ConstantInt::getTrue(MF->getFunction().getContext()),
|
|
|
|
|
nullptr, Succ0MBB, Succ1MBB, &CurMBB,
|
|
|
|
|
CurBuilder->getDebugLoc());
|
|
|
|
|
|
|
|
|
|
// Use emitSwitchCase to actually insert the fast branch sequence for this
|
|
|
|
|
// cond branch.
|
|
|
|
|
emitSwitchCase(CB, &CurMBB, *CurBuilder);
|
2016-03-12 01:28:03 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-22 02:10:38 +08:00
|
|
|
|
void IRTranslator::addSuccessorWithProb(MachineBasicBlock *Src,
|
|
|
|
|
MachineBasicBlock *Dst,
|
|
|
|
|
BranchProbability Prob) {
|
|
|
|
|
if (!FuncInfo.BPI) {
|
|
|
|
|
Src->addSuccessorWithoutProb(Dst);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (Prob.isUnknown())
|
|
|
|
|
Prob = getEdgeProbability(Src, Dst);
|
|
|
|
|
Src->addSuccessor(Dst, Prob);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BranchProbability
|
|
|
|
|
IRTranslator::getEdgeProbability(const MachineBasicBlock *Src,
|
|
|
|
|
const MachineBasicBlock *Dst) const {
|
|
|
|
|
const BasicBlock *SrcBB = Src->getBasicBlock();
|
|
|
|
|
const BasicBlock *DstBB = Dst->getBasicBlock();
|
|
|
|
|
if (!FuncInfo.BPI) {
|
|
|
|
|
// If BPI is not available, set the default probability as 1 / N, where N is
|
|
|
|
|
// the number of successors.
|
|
|
|
|
auto SuccSize = std::max<uint32_t>(succ_size(SrcBB), 1);
|
|
|
|
|
return BranchProbability(1, SuccSize);
|
|
|
|
|
}
|
|
|
|
|
return FuncInfo.BPI->getEdgeProbability(SrcBB, DstBB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IRTranslator::translateSwitch(const User &U, MachineIRBuilder &MIB) {
|
|
|
|
|
using namespace SwitchCG;
|
|
|
|
|
// Extract cases from the switch.
|
|
|
|
|
const SwitchInst &SI = cast<SwitchInst>(U);
|
|
|
|
|
BranchProbabilityInfo *BPI = FuncInfo.BPI;
|
|
|
|
|
CaseClusterVector Clusters;
|
|
|
|
|
Clusters.reserve(SI.getNumCases());
|
|
|
|
|
for (auto &I : SI.cases()) {
|
|
|
|
|
MachineBasicBlock *Succ = &getMBB(*I.getCaseSuccessor());
|
|
|
|
|
assert(Succ && "Could not find successor mbb in mapping");
|
|
|
|
|
const ConstantInt *CaseVal = I.getCaseValue();
|
|
|
|
|
BranchProbability Prob =
|
|
|
|
|
BPI ? BPI->getEdgeProbability(SI.getParent(), I.getSuccessorIndex())
|
|
|
|
|
: BranchProbability(1, SI.getNumCases() + 1);
|
|
|
|
|
Clusters.push_back(CaseCluster::range(CaseVal, CaseVal, Succ, Prob));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MachineBasicBlock *DefaultMBB = &getMBB(*SI.getDefaultDest());
|
|
|
|
|
|
|
|
|
|
// Cluster adjacent cases with the same destination. We do this at all
|
|
|
|
|
// optimization levels because it's cheap to do and will make codegen faster
|
|
|
|
|
// if there are many clusters.
|
|
|
|
|
sortAndRangeify(Clusters);
|
|
|
|
|
|
|
|
|
|
MachineBasicBlock *SwitchMBB = &getMBB(*SI.getParent());
|
|
|
|
|
|
|
|
|
|
// If there is only the default destination, jump there directly.
|
|
|
|
|
if (Clusters.empty()) {
|
|
|
|
|
SwitchMBB->addSuccessor(DefaultMBB);
|
|
|
|
|
if (DefaultMBB != SwitchMBB->getNextNode())
|
|
|
|
|
MIB.buildBr(*DefaultMBB);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-30 02:30:30 +08:00
|
|
|
|
SL->findJumpTables(Clusters, &SI, DefaultMBB, nullptr, nullptr);
|
2020-08-05 01:55:27 +08:00
|
|
|
|
SL->findBitTestClusters(Clusters, &SI);
|
2019-06-22 02:10:38 +08:00
|
|
|
|
|
|
|
|
|
LLVM_DEBUG({
|
|
|
|
|
dbgs() << "Case clusters: ";
|
|
|
|
|
for (const CaseCluster &C : Clusters) {
|
|
|
|
|
if (C.Kind == CC_JumpTable)
|
|
|
|
|
dbgs() << "JT:";
|
|
|
|
|
if (C.Kind == CC_BitTests)
|
|
|
|
|
dbgs() << "BT:";
|
|
|
|
|
|
|
|
|
|
C.Low->getValue().print(dbgs(), true);
|
|
|
|
|
if (C.Low != C.High) {
|
|
|
|
|
dbgs() << '-';
|
|
|
|
|
C.High->getValue().print(dbgs(), true);
|
|
|
|
|
}
|
|
|
|
|
dbgs() << ' ';
|
|
|
|
|
}
|
|
|
|
|
dbgs() << '\n';
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
assert(!Clusters.empty());
|
|
|
|
|
SwitchWorkList WorkList;
|
|
|
|
|
CaseClusterIt First = Clusters.begin();
|
|
|
|
|
CaseClusterIt Last = Clusters.end() - 1;
|
|
|
|
|
auto DefaultProb = getEdgeProbability(SwitchMBB, DefaultMBB);
|
|
|
|
|
WorkList.push_back({SwitchMBB, First, Last, nullptr, nullptr, DefaultProb});
|
|
|
|
|
|
|
|
|
|
// FIXME: At the moment we don't do any splitting optimizations here like
|
|
|
|
|
// SelectionDAG does, so this worklist only has one entry.
|
|
|
|
|
while (!WorkList.empty()) {
|
|
|
|
|
SwitchWorkListItem W = WorkList.back();
|
|
|
|
|
WorkList.pop_back();
|
|
|
|
|
if (!lowerSwitchWorkItem(W, SI.getCondition(), SwitchMBB, DefaultMBB, MIB))
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRTranslator::emitJumpTable(SwitchCG::JumpTable &JT,
|
|
|
|
|
MachineBasicBlock *MBB) {
|
|
|
|
|
// Emit the code for the jump table
|
|
|
|
|
assert(JT.Reg != -1U && "Should lower JT Header first!");
|
|
|
|
|
MachineIRBuilder MIB(*MBB->getParent());
|
|
|
|
|
MIB.setMBB(*MBB);
|
|
|
|
|
MIB.setDebugLoc(CurBuilder->getDebugLoc());
|
|
|
|
|
|
|
|
|
|
Type *PtrIRTy = Type::getInt8PtrTy(MF->getFunction().getContext());
|
|
|
|
|
const LLT PtrTy = getLLTForType(*PtrIRTy, *DL);
|
|
|
|
|
|
|
|
|
|
auto Table = MIB.buildJumpTable(PtrTy, JT.JTI);
|
|
|
|
|
MIB.buildBrJT(Table.getReg(0), JT.JTI, JT.Reg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IRTranslator::emitJumpTableHeader(SwitchCG::JumpTable &JT,
|
|
|
|
|
SwitchCG::JumpTableHeader &JTH,
|
2019-06-28 07:56:34 +08:00
|
|
|
|
MachineBasicBlock *HeaderBB) {
|
|
|
|
|
MachineIRBuilder MIB(*HeaderBB->getParent());
|
|
|
|
|
MIB.setMBB(*HeaderBB);
|
|
|
|
|
MIB.setDebugLoc(CurBuilder->getDebugLoc());
|
2019-06-22 02:10:38 +08:00
|
|
|
|
|
|
|
|
|
const Value &SValue = *JTH.SValue;
|
|
|
|
|
// Subtract the lowest switch case value from the value being switched on.
|
|
|
|
|
const LLT SwitchTy = getLLTForType(*SValue.getType(), *DL);
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register SwitchOpReg = getOrCreateVReg(SValue);
|
2019-06-22 02:10:38 +08:00
|
|
|
|
auto FirstCst = MIB.buildConstant(SwitchTy, JTH.First);
|
|
|
|
|
auto Sub = MIB.buildSub({SwitchTy}, SwitchOpReg, FirstCst);
|
|
|
|
|
|
|
|
|
|
// This value may be smaller or larger than the target's pointer type, and
|
|
|
|
|
// therefore require extension or truncating.
|
|
|
|
|
Type *PtrIRTy = SValue.getType()->getPointerTo();
|
|
|
|
|
const LLT PtrScalarTy = LLT::scalar(DL->getTypeSizeInBits(PtrIRTy));
|
|
|
|
|
Sub = MIB.buildZExtOrTrunc(PtrScalarTy, Sub);
|
|
|
|
|
|
|
|
|
|
JT.Reg = Sub.getReg(0);
|
|
|
|
|
|
|
|
|
|
if (JTH.OmitRangeCheck) {
|
2019-06-28 07:56:34 +08:00
|
|
|
|
if (JT.MBB != HeaderBB->getNextNode())
|
2019-06-22 02:10:38 +08:00
|
|
|
|
MIB.buildBr(*JT.MBB);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Emit the range check for the jump table, and branch to the default block
|
|
|
|
|
// for the switch statement if the value being switched on exceeds the
|
|
|
|
|
// largest case in the switch.
|
|
|
|
|
auto Cst = getOrCreateVReg(
|
|
|
|
|
*ConstantInt::get(SValue.getType(), JTH.Last - JTH.First));
|
|
|
|
|
Cst = MIB.buildZExtOrTrunc(PtrScalarTy, Cst).getReg(0);
|
|
|
|
|
auto Cmp = MIB.buildICmp(CmpInst::ICMP_UGT, LLT::scalar(1), Sub, Cst);
|
|
|
|
|
|
|
|
|
|
auto BrCond = MIB.buildBrCond(Cmp.getReg(0), *JT.Default);
|
|
|
|
|
|
|
|
|
|
// Avoid emitting unnecessary branches to the next block.
|
2019-06-28 07:56:34 +08:00
|
|
|
|
if (JT.MBB != HeaderBB->getNextNode())
|
2019-06-22 02:10:38 +08:00
|
|
|
|
BrCond = MIB.buildBr(*JT.MBB);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRTranslator::emitSwitchCase(SwitchCG::CaseBlock &CB,
|
|
|
|
|
MachineBasicBlock *SwitchBB,
|
|
|
|
|
MachineIRBuilder &MIB) {
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register CondLHS = getOrCreateVReg(*CB.CmpLHS);
|
|
|
|
|
Register Cond;
|
2019-06-22 02:10:38 +08:00
|
|
|
|
DebugLoc OldDbgLoc = MIB.getDebugLoc();
|
|
|
|
|
MIB.setDebugLoc(CB.DbgLoc);
|
|
|
|
|
MIB.setMBB(*CB.ThisBB);
|
|
|
|
|
|
|
|
|
|
if (CB.PredInfo.NoCmp) {
|
|
|
|
|
// Branch or fall through to TrueBB.
|
|
|
|
|
addSuccessorWithProb(CB.ThisBB, CB.TrueBB, CB.TrueProb);
|
|
|
|
|
addMachineCFGPred({SwitchBB->getBasicBlock(), CB.TrueBB->getBasicBlock()},
|
|
|
|
|
CB.ThisBB);
|
|
|
|
|
CB.ThisBB->normalizeSuccProbs();
|
|
|
|
|
if (CB.TrueBB != CB.ThisBB->getNextNode())
|
|
|
|
|
MIB.buildBr(*CB.TrueBB);
|
|
|
|
|
MIB.setDebugLoc(OldDbgLoc);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const LLT i1Ty = LLT::scalar(1);
|
|
|
|
|
// Build the compare.
|
|
|
|
|
if (!CB.CmpMHS) {
|
2020-08-25 05:10:38 +08:00
|
|
|
|
const auto *CI = dyn_cast<ConstantInt>(CB.CmpRHS);
|
|
|
|
|
// For conditional branch lowering, we might try to do something silly like
|
|
|
|
|
// emit an G_ICMP to compare an existing G_ICMP i1 result with true. If so,
|
|
|
|
|
// just re-use the existing condition vreg.
|
2021-02-01 20:43:33 +08:00
|
|
|
|
if (MRI->getType(CondLHS).getSizeInBits() == 1 && CI &&
|
|
|
|
|
CI->getZExtValue() == 1 && CB.PredInfo.Pred == CmpInst::ICMP_EQ) {
|
2020-08-25 05:10:38 +08:00
|
|
|
|
Cond = CondLHS;
|
|
|
|
|
} else {
|
|
|
|
|
Register CondRHS = getOrCreateVReg(*CB.CmpRHS);
|
|
|
|
|
if (CmpInst::isFPPredicate(CB.PredInfo.Pred))
|
|
|
|
|
Cond =
|
|
|
|
|
MIB.buildFCmp(CB.PredInfo.Pred, i1Ty, CondLHS, CondRHS).getReg(0);
|
|
|
|
|
else
|
|
|
|
|
Cond =
|
|
|
|
|
MIB.buildICmp(CB.PredInfo.Pred, i1Ty, CondLHS, CondRHS).getReg(0);
|
|
|
|
|
}
|
2019-06-22 02:10:38 +08:00
|
|
|
|
} else {
|
2019-09-24 08:09:23 +08:00
|
|
|
|
assert(CB.PredInfo.Pred == CmpInst::ICMP_SLE &&
|
|
|
|
|
"Can only handle SLE ranges");
|
2019-06-22 02:10:38 +08:00
|
|
|
|
|
|
|
|
|
const APInt& Low = cast<ConstantInt>(CB.CmpLHS)->getValue();
|
|
|
|
|
const APInt& High = cast<ConstantInt>(CB.CmpRHS)->getValue();
|
|
|
|
|
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register CmpOpReg = getOrCreateVReg(*CB.CmpMHS);
|
2019-06-22 02:10:38 +08:00
|
|
|
|
if (cast<ConstantInt>(CB.CmpLHS)->isMinValue(true)) {
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register CondRHS = getOrCreateVReg(*CB.CmpRHS);
|
2019-06-22 02:10:38 +08:00
|
|
|
|
Cond =
|
2019-09-24 08:09:23 +08:00
|
|
|
|
MIB.buildICmp(CmpInst::ICMP_SLE, i1Ty, CmpOpReg, CondRHS).getReg(0);
|
2019-06-22 02:10:38 +08:00
|
|
|
|
} else {
|
2020-02-14 03:30:50 +08:00
|
|
|
|
const LLT CmpTy = MRI->getType(CmpOpReg);
|
2019-06-22 02:10:38 +08:00
|
|
|
|
auto Sub = MIB.buildSub({CmpTy}, CmpOpReg, CondLHS);
|
|
|
|
|
auto Diff = MIB.buildConstant(CmpTy, High - Low);
|
|
|
|
|
Cond = MIB.buildICmp(CmpInst::ICMP_ULE, i1Ty, Sub, Diff).getReg(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update successor info
|
|
|
|
|
addSuccessorWithProb(CB.ThisBB, CB.TrueBB, CB.TrueProb);
|
|
|
|
|
|
|
|
|
|
addMachineCFGPred({SwitchBB->getBasicBlock(), CB.TrueBB->getBasicBlock()},
|
|
|
|
|
CB.ThisBB);
|
|
|
|
|
|
|
|
|
|
// TrueBB and FalseBB are always different unless the incoming IR is
|
|
|
|
|
// degenerate. This only happens when running llc on weird IR.
|
|
|
|
|
if (CB.TrueBB != CB.FalseBB)
|
|
|
|
|
addSuccessorWithProb(CB.ThisBB, CB.FalseBB, CB.FalseProb);
|
|
|
|
|
CB.ThisBB->normalizeSuccProbs();
|
|
|
|
|
|
2020-08-25 05:10:38 +08:00
|
|
|
|
addMachineCFGPred({SwitchBB->getBasicBlock(), CB.FalseBB->getBasicBlock()},
|
|
|
|
|
CB.ThisBB);
|
2019-06-22 02:10:38 +08:00
|
|
|
|
|
|
|
|
|
MIB.buildBrCond(Cond, *CB.TrueBB);
|
|
|
|
|
MIB.buildBr(*CB.FalseBB);
|
|
|
|
|
MIB.setDebugLoc(OldDbgLoc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IRTranslator::lowerJumpTableWorkItem(SwitchCG::SwitchWorkListItem W,
|
|
|
|
|
MachineBasicBlock *SwitchMBB,
|
2019-06-28 07:56:34 +08:00
|
|
|
|
MachineBasicBlock *CurMBB,
|
2019-06-22 02:10:38 +08:00
|
|
|
|
MachineBasicBlock *DefaultMBB,
|
|
|
|
|
MachineIRBuilder &MIB,
|
|
|
|
|
MachineFunction::iterator BBI,
|
|
|
|
|
BranchProbability UnhandledProbs,
|
|
|
|
|
SwitchCG::CaseClusterIt I,
|
|
|
|
|
MachineBasicBlock *Fallthrough,
|
|
|
|
|
bool FallthroughUnreachable) {
|
|
|
|
|
using namespace SwitchCG;
|
|
|
|
|
MachineFunction *CurMF = SwitchMBB->getParent();
|
|
|
|
|
// FIXME: Optimize away range check based on pivot comparisons.
|
|
|
|
|
JumpTableHeader *JTH = &SL->JTCases[I->JTCasesIndex].first;
|
|
|
|
|
SwitchCG::JumpTable *JT = &SL->JTCases[I->JTCasesIndex].second;
|
|
|
|
|
BranchProbability DefaultProb = W.DefaultProb;
|
|
|
|
|
|
|
|
|
|
// The jump block hasn't been inserted yet; insert it here.
|
|
|
|
|
MachineBasicBlock *JumpMBB = JT->MBB;
|
|
|
|
|
CurMF->insert(BBI, JumpMBB);
|
|
|
|
|
|
|
|
|
|
// Since the jump table block is separate from the switch block, we need
|
|
|
|
|
// to keep track of it as a machine predecessor to the default block,
|
|
|
|
|
// otherwise we lose the phi edges.
|
|
|
|
|
addMachineCFGPred({SwitchMBB->getBasicBlock(), DefaultMBB->getBasicBlock()},
|
2019-06-28 07:56:34 +08:00
|
|
|
|
CurMBB);
|
2019-06-22 02:10:38 +08:00
|
|
|
|
addMachineCFGPred({SwitchMBB->getBasicBlock(), DefaultMBB->getBasicBlock()},
|
|
|
|
|
JumpMBB);
|
|
|
|
|
|
|
|
|
|
auto JumpProb = I->Prob;
|
|
|
|
|
auto FallthroughProb = UnhandledProbs;
|
|
|
|
|
|
|
|
|
|
// If the default statement is a target of the jump table, we evenly
|
|
|
|
|
// distribute the default probability to successors of CurMBB. Also
|
|
|
|
|
// update the probability on the edge from JumpMBB to Fallthrough.
|
|
|
|
|
for (MachineBasicBlock::succ_iterator SI = JumpMBB->succ_begin(),
|
|
|
|
|
SE = JumpMBB->succ_end();
|
|
|
|
|
SI != SE; ++SI) {
|
|
|
|
|
if (*SI == DefaultMBB) {
|
|
|
|
|
JumpProb += DefaultProb / 2;
|
|
|
|
|
FallthroughProb -= DefaultProb / 2;
|
|
|
|
|
JumpMBB->setSuccProbability(SI, DefaultProb / 2);
|
|
|
|
|
JumpMBB->normalizeSuccProbs();
|
2019-06-28 07:56:34 +08:00
|
|
|
|
} else {
|
|
|
|
|
// Also record edges from the jump table block to it's successors.
|
|
|
|
|
addMachineCFGPred({SwitchMBB->getBasicBlock(), (*SI)->getBasicBlock()},
|
|
|
|
|
JumpMBB);
|
2019-06-22 02:10:38 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Skip the range check if the fallthrough block is unreachable.
|
|
|
|
|
if (FallthroughUnreachable)
|
|
|
|
|
JTH->OmitRangeCheck = true;
|
|
|
|
|
|
|
|
|
|
if (!JTH->OmitRangeCheck)
|
|
|
|
|
addSuccessorWithProb(CurMBB, Fallthrough, FallthroughProb);
|
|
|
|
|
addSuccessorWithProb(CurMBB, JumpMBB, JumpProb);
|
|
|
|
|
CurMBB->normalizeSuccProbs();
|
|
|
|
|
|
|
|
|
|
// The jump table header will be inserted in our current block, do the
|
|
|
|
|
// range check, and fall through to our fallthrough block.
|
|
|
|
|
JTH->HeaderBB = CurMBB;
|
|
|
|
|
JT->Default = Fallthrough; // FIXME: Move Default to JumpTableHeader.
|
|
|
|
|
|
|
|
|
|
// If we're in the right place, emit the jump table header right now.
|
|
|
|
|
if (CurMBB == SwitchMBB) {
|
2019-06-28 07:56:34 +08:00
|
|
|
|
if (!emitJumpTableHeader(*JT, *JTH, CurMBB))
|
2019-06-22 02:10:38 +08:00
|
|
|
|
return false;
|
|
|
|
|
JTH->Emitted = true;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
bool IRTranslator::lowerSwitchRangeWorkItem(SwitchCG::CaseClusterIt I,
|
|
|
|
|
Value *Cond,
|
|
|
|
|
MachineBasicBlock *Fallthrough,
|
|
|
|
|
bool FallthroughUnreachable,
|
|
|
|
|
BranchProbability UnhandledProbs,
|
|
|
|
|
MachineBasicBlock *CurMBB,
|
|
|
|
|
MachineIRBuilder &MIB,
|
|
|
|
|
MachineBasicBlock *SwitchMBB) {
|
|
|
|
|
using namespace SwitchCG;
|
|
|
|
|
const Value *RHS, *LHS, *MHS;
|
|
|
|
|
CmpInst::Predicate Pred;
|
|
|
|
|
if (I->Low == I->High) {
|
|
|
|
|
// Check Cond == I->Low.
|
|
|
|
|
Pred = CmpInst::ICMP_EQ;
|
|
|
|
|
LHS = Cond;
|
|
|
|
|
RHS = I->Low;
|
|
|
|
|
MHS = nullptr;
|
|
|
|
|
} else {
|
|
|
|
|
// Check I->Low <= Cond <= I->High.
|
2019-09-24 08:09:23 +08:00
|
|
|
|
Pred = CmpInst::ICMP_SLE;
|
2019-06-22 02:10:38 +08:00
|
|
|
|
LHS = I->Low;
|
|
|
|
|
MHS = Cond;
|
|
|
|
|
RHS = I->High;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If Fallthrough is unreachable, fold away the comparison.
|
|
|
|
|
// The false probability is the sum of all unhandled cases.
|
|
|
|
|
CaseBlock CB(Pred, FallthroughUnreachable, LHS, RHS, MHS, I->MBB, Fallthrough,
|
|
|
|
|
CurMBB, MIB.getDebugLoc(), I->Prob, UnhandledProbs);
|
|
|
|
|
|
|
|
|
|
emitSwitchCase(CB, SwitchMBB, MIB);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-05 01:55:27 +08:00
|
|
|
|
void IRTranslator::emitBitTestHeader(SwitchCG::BitTestBlock &B,
|
|
|
|
|
MachineBasicBlock *SwitchBB) {
|
|
|
|
|
MachineIRBuilder &MIB = *CurBuilder;
|
|
|
|
|
MIB.setMBB(*SwitchBB);
|
|
|
|
|
|
|
|
|
|
// Subtract the minimum value.
|
|
|
|
|
Register SwitchOpReg = getOrCreateVReg(*B.SValue);
|
|
|
|
|
|
|
|
|
|
LLT SwitchOpTy = MRI->getType(SwitchOpReg);
|
|
|
|
|
Register MinValReg = MIB.buildConstant(SwitchOpTy, B.First).getReg(0);
|
|
|
|
|
auto RangeSub = MIB.buildSub(SwitchOpTy, SwitchOpReg, MinValReg);
|
|
|
|
|
|
|
|
|
|
// Ensure that the type will fit the mask value.
|
|
|
|
|
LLT MaskTy = SwitchOpTy;
|
|
|
|
|
for (unsigned I = 0, E = B.Cases.size(); I != E; ++I) {
|
|
|
|
|
if (!isUIntN(SwitchOpTy.getSizeInBits(), B.Cases[I].Mask)) {
|
|
|
|
|
// Switch table case range are encoded into series of masks.
|
|
|
|
|
// Just use pointer type, it's guaranteed to fit.
|
|
|
|
|
MaskTy = LLT::scalar(64);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Register SubReg = RangeSub.getReg(0);
|
|
|
|
|
if (SwitchOpTy != MaskTy)
|
|
|
|
|
SubReg = MIB.buildZExtOrTrunc(MaskTy, SubReg).getReg(0);
|
|
|
|
|
|
|
|
|
|
B.RegVT = getMVTForLLT(MaskTy);
|
|
|
|
|
B.Reg = SubReg;
|
|
|
|
|
|
|
|
|
|
MachineBasicBlock *MBB = B.Cases[0].ThisBB;
|
|
|
|
|
|
|
|
|
|
if (!B.OmitRangeCheck)
|
|
|
|
|
addSuccessorWithProb(SwitchBB, B.Default, B.DefaultProb);
|
|
|
|
|
addSuccessorWithProb(SwitchBB, MBB, B.Prob);
|
|
|
|
|
|
|
|
|
|
SwitchBB->normalizeSuccProbs();
|
|
|
|
|
|
|
|
|
|
if (!B.OmitRangeCheck) {
|
|
|
|
|
// Conditional branch to the default block.
|
|
|
|
|
auto RangeCst = MIB.buildConstant(SwitchOpTy, B.Range);
|
|
|
|
|
auto RangeCmp = MIB.buildICmp(CmpInst::Predicate::ICMP_UGT, LLT::scalar(1),
|
|
|
|
|
RangeSub, RangeCst);
|
|
|
|
|
MIB.buildBrCond(RangeCmp, *B.Default);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Avoid emitting unnecessary branches to the next block.
|
|
|
|
|
if (MBB != SwitchBB->getNextNode())
|
|
|
|
|
MIB.buildBr(*MBB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void IRTranslator::emitBitTestCase(SwitchCG::BitTestBlock &BB,
|
|
|
|
|
MachineBasicBlock *NextMBB,
|
|
|
|
|
BranchProbability BranchProbToNext,
|
|
|
|
|
Register Reg, SwitchCG::BitTestCase &B,
|
|
|
|
|
MachineBasicBlock *SwitchBB) {
|
|
|
|
|
MachineIRBuilder &MIB = *CurBuilder;
|
|
|
|
|
MIB.setMBB(*SwitchBB);
|
|
|
|
|
|
|
|
|
|
LLT SwitchTy = getLLTForMVT(BB.RegVT);
|
|
|
|
|
Register Cmp;
|
|
|
|
|
unsigned PopCount = countPopulation(B.Mask);
|
|
|
|
|
if (PopCount == 1) {
|
|
|
|
|
// Testing for a single bit; just compare the shift count with what it
|
|
|
|
|
// would need to be to shift a 1 bit in that position.
|
|
|
|
|
auto MaskTrailingZeros =
|
|
|
|
|
MIB.buildConstant(SwitchTy, countTrailingZeros(B.Mask));
|
|
|
|
|
Cmp =
|
|
|
|
|
MIB.buildICmp(ICmpInst::ICMP_EQ, LLT::scalar(1), Reg, MaskTrailingZeros)
|
|
|
|
|
.getReg(0);
|
|
|
|
|
} else if (PopCount == BB.Range) {
|
|
|
|
|
// There is only one zero bit in the range, test for it directly.
|
|
|
|
|
auto MaskTrailingOnes =
|
|
|
|
|
MIB.buildConstant(SwitchTy, countTrailingOnes(B.Mask));
|
|
|
|
|
Cmp = MIB.buildICmp(CmpInst::ICMP_NE, LLT::scalar(1), Reg, MaskTrailingOnes)
|
|
|
|
|
.getReg(0);
|
|
|
|
|
} else {
|
|
|
|
|
// Make desired shift.
|
|
|
|
|
auto CstOne = MIB.buildConstant(SwitchTy, 1);
|
|
|
|
|
auto SwitchVal = MIB.buildShl(SwitchTy, CstOne, Reg);
|
|
|
|
|
|
|
|
|
|
// Emit bit tests and jumps.
|
|
|
|
|
auto CstMask = MIB.buildConstant(SwitchTy, B.Mask);
|
|
|
|
|
auto AndOp = MIB.buildAnd(SwitchTy, SwitchVal, CstMask);
|
|
|
|
|
auto CstZero = MIB.buildConstant(SwitchTy, 0);
|
|
|
|
|
Cmp = MIB.buildICmp(CmpInst::ICMP_NE, LLT::scalar(1), AndOp, CstZero)
|
|
|
|
|
.getReg(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The branch probability from SwitchBB to B.TargetBB is B.ExtraProb.
|
|
|
|
|
addSuccessorWithProb(SwitchBB, B.TargetBB, B.ExtraProb);
|
|
|
|
|
// The branch probability from SwitchBB to NextMBB is BranchProbToNext.
|
|
|
|
|
addSuccessorWithProb(SwitchBB, NextMBB, BranchProbToNext);
|
|
|
|
|
// It is not guaranteed that the sum of B.ExtraProb and BranchProbToNext is
|
|
|
|
|
// one as they are relative probabilities (and thus work more like weights),
|
|
|
|
|
// and hence we need to normalize them to let the sum of them become one.
|
|
|
|
|
SwitchBB->normalizeSuccProbs();
|
|
|
|
|
|
|
|
|
|
// Record the fact that the IR edge from the header to the bit test target
|
|
|
|
|
// will go through our new block. Neeeded for PHIs to have nodes added.
|
|
|
|
|
addMachineCFGPred({BB.Parent->getBasicBlock(), B.TargetBB->getBasicBlock()},
|
|
|
|
|
SwitchBB);
|
|
|
|
|
|
|
|
|
|
MIB.buildBrCond(Cmp, *B.TargetBB);
|
|
|
|
|
|
|
|
|
|
// Avoid emitting unnecessary branches to the next block.
|
|
|
|
|
if (NextMBB != SwitchBB->getNextNode())
|
|
|
|
|
MIB.buildBr(*NextMBB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IRTranslator::lowerBitTestWorkItem(
|
|
|
|
|
SwitchCG::SwitchWorkListItem W, MachineBasicBlock *SwitchMBB,
|
|
|
|
|
MachineBasicBlock *CurMBB, MachineBasicBlock *DefaultMBB,
|
|
|
|
|
MachineIRBuilder &MIB, MachineFunction::iterator BBI,
|
|
|
|
|
BranchProbability DefaultProb, BranchProbability UnhandledProbs,
|
|
|
|
|
SwitchCG::CaseClusterIt I, MachineBasicBlock *Fallthrough,
|
|
|
|
|
bool FallthroughUnreachable) {
|
|
|
|
|
using namespace SwitchCG;
|
|
|
|
|
MachineFunction *CurMF = SwitchMBB->getParent();
|
|
|
|
|
// FIXME: Optimize away range check based on pivot comparisons.
|
|
|
|
|
BitTestBlock *BTB = &SL->BitTestCases[I->BTCasesIndex];
|
|
|
|
|
// The bit test blocks haven't been inserted yet; insert them here.
|
|
|
|
|
for (BitTestCase &BTC : BTB->Cases)
|
|
|
|
|
CurMF->insert(BBI, BTC.ThisBB);
|
|
|
|
|
|
|
|
|
|
// Fill in fields of the BitTestBlock.
|
|
|
|
|
BTB->Parent = CurMBB;
|
|
|
|
|
BTB->Default = Fallthrough;
|
|
|
|
|
|
|
|
|
|
BTB->DefaultProb = UnhandledProbs;
|
|
|
|
|
// If the cases in bit test don't form a contiguous range, we evenly
|
|
|
|
|
// distribute the probability on the edge to Fallthrough to two
|
|
|
|
|
// successors of CurMBB.
|
|
|
|
|
if (!BTB->ContiguousRange) {
|
|
|
|
|
BTB->Prob += DefaultProb / 2;
|
|
|
|
|
BTB->DefaultProb -= DefaultProb / 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (FallthroughUnreachable) {
|
|
|
|
|
// Skip the range check if the fallthrough block is unreachable.
|
|
|
|
|
BTB->OmitRangeCheck = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we're in the right place, emit the bit test header right now.
|
|
|
|
|
if (CurMBB == SwitchMBB) {
|
|
|
|
|
emitBitTestHeader(*BTB, SwitchMBB);
|
|
|
|
|
BTB->Emitted = true;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-22 02:10:38 +08:00
|
|
|
|
bool IRTranslator::lowerSwitchWorkItem(SwitchCG::SwitchWorkListItem W,
|
|
|
|
|
Value *Cond,
|
|
|
|
|
MachineBasicBlock *SwitchMBB,
|
|
|
|
|
MachineBasicBlock *DefaultMBB,
|
|
|
|
|
MachineIRBuilder &MIB) {
|
|
|
|
|
using namespace SwitchCG;
|
|
|
|
|
MachineFunction *CurMF = FuncInfo.MF;
|
|
|
|
|
MachineBasicBlock *NextMBB = nullptr;
|
|
|
|
|
MachineFunction::iterator BBI(W.MBB);
|
|
|
|
|
if (++BBI != FuncInfo.MF->end())
|
|
|
|
|
NextMBB = &*BBI;
|
|
|
|
|
|
|
|
|
|
if (EnableOpts) {
|
|
|
|
|
// Here, we order cases by probability so the most likely case will be
|
|
|
|
|
// checked first. However, two clusters can have the same probability in
|
|
|
|
|
// which case their relative ordering is non-deterministic. So we use Low
|
|
|
|
|
// as a tie-breaker as clusters are guaranteed to never overlap.
|
|
|
|
|
llvm::sort(W.FirstCluster, W.LastCluster + 1,
|
|
|
|
|
[](const CaseCluster &a, const CaseCluster &b) {
|
|
|
|
|
return a.Prob != b.Prob
|
|
|
|
|
? a.Prob > b.Prob
|
|
|
|
|
: a.Low->getValue().slt(b.Low->getValue());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Rearrange the case blocks so that the last one falls through if possible
|
|
|
|
|
// without changing the order of probabilities.
|
|
|
|
|
for (CaseClusterIt I = W.LastCluster; I > W.FirstCluster;) {
|
|
|
|
|
--I;
|
|
|
|
|
if (I->Prob > W.LastCluster->Prob)
|
|
|
|
|
break;
|
|
|
|
|
if (I->Kind == CC_Range && I->MBB == NextMBB) {
|
|
|
|
|
std::swap(*I, *W.LastCluster);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compute total probability.
|
|
|
|
|
BranchProbability DefaultProb = W.DefaultProb;
|
|
|
|
|
BranchProbability UnhandledProbs = DefaultProb;
|
|
|
|
|
for (CaseClusterIt I = W.FirstCluster; I <= W.LastCluster; ++I)
|
|
|
|
|
UnhandledProbs += I->Prob;
|
|
|
|
|
|
|
|
|
|
MachineBasicBlock *CurMBB = W.MBB;
|
|
|
|
|
for (CaseClusterIt I = W.FirstCluster, E = W.LastCluster; I <= E; ++I) {
|
|
|
|
|
bool FallthroughUnreachable = false;
|
|
|
|
|
MachineBasicBlock *Fallthrough;
|
|
|
|
|
if (I == W.LastCluster) {
|
|
|
|
|
// For the last cluster, fall through to the default destination.
|
|
|
|
|
Fallthrough = DefaultMBB;
|
|
|
|
|
FallthroughUnreachable = isa<UnreachableInst>(
|
|
|
|
|
DefaultMBB->getBasicBlock()->getFirstNonPHIOrDbg());
|
|
|
|
|
} else {
|
|
|
|
|
Fallthrough = CurMF->CreateMachineBasicBlock(CurMBB->getBasicBlock());
|
|
|
|
|
CurMF->insert(BBI, Fallthrough);
|
|
|
|
|
}
|
|
|
|
|
UnhandledProbs -= I->Prob;
|
|
|
|
|
|
|
|
|
|
switch (I->Kind) {
|
|
|
|
|
case CC_BitTests: {
|
2020-08-05 01:55:27 +08:00
|
|
|
|
if (!lowerBitTestWorkItem(W, SwitchMBB, CurMBB, DefaultMBB, MIB, BBI,
|
|
|
|
|
DefaultProb, UnhandledProbs, I, Fallthrough,
|
|
|
|
|
FallthroughUnreachable)) {
|
|
|
|
|
LLVM_DEBUG(dbgs() << "Failed to lower bit test for switch");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2019-06-22 02:10:38 +08:00
|
|
|
|
}
|
2020-08-05 01:55:27 +08:00
|
|
|
|
|
2019-06-22 02:10:38 +08:00
|
|
|
|
case CC_JumpTable: {
|
2019-06-28 07:56:34 +08:00
|
|
|
|
if (!lowerJumpTableWorkItem(W, SwitchMBB, CurMBB, DefaultMBB, MIB, BBI,
|
2019-06-22 02:10:38 +08:00
|
|
|
|
UnhandledProbs, I, Fallthrough,
|
|
|
|
|
FallthroughUnreachable)) {
|
|
|
|
|
LLVM_DEBUG(dbgs() << "Failed to lower jump table");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CC_Range: {
|
|
|
|
|
if (!lowerSwitchRangeWorkItem(I, Cond, Fallthrough,
|
|
|
|
|
FallthroughUnreachable, UnhandledProbs,
|
|
|
|
|
CurMBB, MIB, SwitchMBB)) {
|
|
|
|
|
LLVM_DEBUG(dbgs() << "Failed to lower switch range");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CurMBB = Fallthrough;
|
|
|
|
|
}
|
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);
|
|
|
|
|
|
2019-06-25 00:16:12 +08:00
|
|
|
|
const Register Tgt = getOrCreateVReg(*BrInst.getAddress());
|
2017-01-30 17:13:18 +08:00
|
|
|
|
MIRBuilder.buildBrIndirect(Tgt);
|
|
|
|
|
|
|
|
|
|
// Link successors.
|
2020-05-08 07:25:34 +08:00
|
|
|
|
SmallPtrSet<const BasicBlock *, 32> AddedSuccessors;
|
2017-01-30 17:13:18 +08:00
|
|
|
|
MachineBasicBlock &CurBB = MIRBuilder.getMBB();
|
2020-05-08 07:25:34 +08:00
|
|
|
|
for (const BasicBlock *Succ : successors(&BrInst)) {
|
|
|
|
|
// It's legal for indirectbr instructions to have duplicate blocks in the
|
|
|
|
|
// destination list. We don't allow this in MIR. Skip anything that's
|
|
|
|
|
// already a successor.
|
|
|
|
|
if (!AddedSuccessors.insert(Succ).second)
|
|
|
|
|
continue;
|
2017-03-16 02:22:33 +08:00
|
|
|
|
CurBB.addSuccessor(&getMBB(*Succ));
|
2020-05-08 07:25:34 +08:00
|
|
|
|
}
|
2017-01-30 17:13:18 +08:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-24 16:40:13 +08:00
|
|
|
|
static bool isSwiftError(const Value *V) {
|
|
|
|
|
if (auto Arg = dyn_cast<Argument>(V))
|
|
|
|
|
return Arg->hasSwiftErrorAttr();
|
|
|
|
|
if (auto AI = dyn_cast<AllocaInst>(V))
|
|
|
|
|
return AI->isSwiftError();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
2017-12-01 04:06:02 +08:00
|
|
|
|
if (DL->getTypeStoreSize(LI.getType()) == 0)
|
|
|
|
|
return true;
|
|
|
|
|
|
2019-06-24 23:50:29 +08:00
|
|
|
|
ArrayRef<Register> Regs = getOrCreateVRegs(LI);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
ArrayRef<uint64_t> Offsets = *VMap.getOffsets(LI);
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Base = getOrCreateVReg(*LI.getPointerOperand());
|
2018-05-16 18:32:02 +08:00
|
|
|
|
|
2019-05-14 17:25:17 +08:00
|
|
|
|
Type *OffsetIRTy = DL->getIntPtrType(LI.getPointerOperandType());
|
|
|
|
|
LLT OffsetTy = getLLTForType(*OffsetIRTy, *DL);
|
|
|
|
|
|
2019-05-24 16:40:13 +08:00
|
|
|
|
if (CLI->supportSwiftError() && isSwiftError(LI.getPointerOperand())) {
|
|
|
|
|
assert(Regs.size() == 1 && "swifterror should be single pointer");
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register VReg = SwiftError.getOrCreateVRegUseAt(&LI, &MIRBuilder.getMBB(),
|
2019-05-24 16:40:13 +08:00
|
|
|
|
LI.getPointerOperand());
|
|
|
|
|
MIRBuilder.buildCopy(Regs[0], VReg);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-13 03:10:42 +08:00
|
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
|
MachineMemOperand::Flags Flags = TLI.getLoadMemOperandFlags(LI, *DL);
|
|
|
|
|
|
2019-07-21 22:07:54 +08:00
|
|
|
|
const MDNode *Ranges =
|
|
|
|
|
Regs.size() == 1 ? LI.getMetadata(LLVMContext::MD_range) : nullptr;
|
2018-05-16 18:32:02 +08:00
|
|
|
|
for (unsigned i = 0; i < Regs.size(); ++i) {
|
2019-06-24 23:50:29 +08:00
|
|
|
|
Register Addr;
|
[globalisel] Rename G_GEP to G_PTR_ADD
Summary:
G_GEP is rather poorly named. It's a simple pointer+scalar addition and
doesn't support any of the complexities of getelementptr. I therefore
propose that we rename it. There's a G_PTR_MASK so let's follow that
convention and go with G_PTR_ADD
Reviewers: volkan, aditya_nandakumar, bogner, rovka, arsenm
Subscribers: sdardis, jvesely, wdng, nhaehnle, hiraditya, jrtc27, atanasyan, arphaman, Petar.Avramovic, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D69734
2019-11-02 04:18:00 +08:00
|
|
|
|
MIRBuilder.materializePtrAdd(Addr, Base, OffsetTy, Offsets[i] / 8);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
|
|
|
|
|
MachinePointerInfo Ptr(LI.getPointerOperand(), Offsets[i] / 8);
|
2020-03-31 17:43:50 +08:00
|
|
|
|
Align BaseAlign = getMemOpAlign(LI);
|
2019-11-15 04:11:00 +08:00
|
|
|
|
AAMDNodes AAMetadata;
|
|
|
|
|
LI.getAAMetadata(AAMetadata);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
auto MMO = MF->getMachineMemOperand(
|
2020-03-31 17:43:50 +08:00
|
|
|
|
Ptr, Flags, MRI->getType(Regs[i]).getSizeInBytes(),
|
|
|
|
|
commonAlignment(BaseAlign, Offsets[i] / 8), AAMetadata, Ranges,
|
2018-05-16 18:32:02 +08:00
|
|
|
|
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);
|
2017-12-01 04:06:02 +08:00
|
|
|
|
if (DL->getTypeStoreSize(SI.getValueOperand()->getType()) == 0)
|
|
|
|
|
return true;
|
|
|
|
|
|
2019-06-24 23:50:29 +08:00
|
|
|
|
ArrayRef<Register> Vals = getOrCreateVRegs(*SI.getValueOperand());
|
2018-05-16 18:32:02 +08:00
|
|
|
|
ArrayRef<uint64_t> Offsets = *VMap.getOffsets(*SI.getValueOperand());
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Base = getOrCreateVReg(*SI.getPointerOperand());
|
2018-05-16 18:32:02 +08:00
|
|
|
|
|
2019-05-14 17:25:17 +08:00
|
|
|
|
Type *OffsetIRTy = DL->getIntPtrType(SI.getPointerOperandType());
|
|
|
|
|
LLT OffsetTy = getLLTForType(*OffsetIRTy, *DL);
|
|
|
|
|
|
2019-05-24 16:40:13 +08:00
|
|
|
|
if (CLI->supportSwiftError() && isSwiftError(SI.getPointerOperand())) {
|
|
|
|
|
assert(Vals.size() == 1 && "swifterror should be single pointer");
|
|
|
|
|
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register VReg = SwiftError.getOrCreateVRegDefAt(&SI, &MIRBuilder.getMBB(),
|
2019-05-24 16:40:13 +08:00
|
|
|
|
SI.getPointerOperand());
|
|
|
|
|
MIRBuilder.buildCopy(VReg, Vals[0]);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-13 03:10:42 +08:00
|
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
|
MachineMemOperand::Flags Flags = TLI.getStoreMemOperandFlags(SI, *DL);
|
|
|
|
|
|
2018-05-16 18:32:02 +08:00
|
|
|
|
for (unsigned i = 0; i < Vals.size(); ++i) {
|
2019-06-24 23:50:29 +08:00
|
|
|
|
Register Addr;
|
[globalisel] Rename G_GEP to G_PTR_ADD
Summary:
G_GEP is rather poorly named. It's a simple pointer+scalar addition and
doesn't support any of the complexities of getelementptr. I therefore
propose that we rename it. There's a G_PTR_MASK so let's follow that
convention and go with G_PTR_ADD
Reviewers: volkan, aditya_nandakumar, bogner, rovka, arsenm
Subscribers: sdardis, jvesely, wdng, nhaehnle, hiraditya, jrtc27, atanasyan, arphaman, Petar.Avramovic, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D69734
2019-11-02 04:18:00 +08:00
|
|
|
|
MIRBuilder.materializePtrAdd(Addr, Base, OffsetTy, Offsets[i] / 8);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
|
|
|
|
|
MachinePointerInfo Ptr(SI.getPointerOperand(), Offsets[i] / 8);
|
2020-03-31 17:43:50 +08:00
|
|
|
|
Align BaseAlign = getMemOpAlign(SI);
|
2019-11-15 04:11:00 +08:00
|
|
|
|
AAMDNodes AAMetadata;
|
|
|
|
|
SI.getAAMetadata(AAMetadata);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
auto MMO = MF->getMachineMemOperand(
|
2020-03-31 17:43:50 +08:00
|
|
|
|
Ptr, Flags, MRI->getType(Vals[i]).getSizeInBytes(),
|
|
|
|
|
commonAlignment(BaseAlign, Offsets[i] / 8), AAMetadata, nullptr,
|
2018-05-16 18:32:02 +08:00
|
|
|
|
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);
|
2019-06-24 23:50:29 +08:00
|
|
|
|
ArrayRef<Register> SrcRegs = getOrCreateVRegs(*Src);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
ArrayRef<uint64_t> Offsets = *VMap.getOffsets(*Src);
|
2019-04-12 10:02:06 +08:00
|
|
|
|
unsigned Idx = llvm::lower_bound(Offsets, Offset) - Offsets.begin();
|
2018-05-16 18:32:02 +08:00
|
|
|
|
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);
|
2019-06-24 23:50:29 +08:00
|
|
|
|
ArrayRef<Register> SrcRegs = getOrCreateVRegs(*Src);
|
|
|
|
|
ArrayRef<Register> InsertedRegs = getOrCreateVRegs(*U.getOperand(1));
|
2018-05-16 18:32:02 +08:00
|
|
|
|
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) {
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Tst = getOrCreateVReg(*U.getOperand(0));
|
2019-06-24 23:50:29 +08:00
|
|
|
|
ArrayRef<Register> ResRegs = getOrCreateVRegs(U);
|
|
|
|
|
ArrayRef<Register> Op0Regs = getOrCreateVRegs(*U.getOperand(1));
|
|
|
|
|
ArrayRef<Register> Op1Regs = getOrCreateVRegs(*U.getOperand(2));
|
2018-05-16 18:32:02 +08:00
|
|
|
|
|
2019-02-07 03:57:06 +08:00
|
|
|
|
uint16_t Flags = 0;
|
2020-05-19 21:27:25 +08:00
|
|
|
|
if (const SelectInst *SI = dyn_cast<SelectInst>(&U))
|
|
|
|
|
Flags = MachineInstr::copyFlagsFromInstruction(*SI);
|
2019-02-07 03:57:06 +08:00
|
|
|
|
|
2018-12-19 01:54:52 +08:00
|
|
|
|
for (unsigned i = 0; i < ResRegs.size(); ++i) {
|
2020-01-16 20:09:48 +08:00
|
|
|
|
MIRBuilder.buildSelect(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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-17 21:36:01 +08:00
|
|
|
|
bool IRTranslator::translateCopy(const User &U, const Value &V,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
Register Src = getOrCreateVReg(V);
|
|
|
|
|
auto &Regs = *VMap.getVRegs(U);
|
|
|
|
|
if (Regs.empty()) {
|
|
|
|
|
Regs.push_back(Src);
|
|
|
|
|
VMap.getOffsets(U)->push_back(0);
|
|
|
|
|
} else {
|
|
|
|
|
// If we already assigned a vreg for this instruction, we can't change that.
|
|
|
|
|
// Emit a copy to satisfy the users we already emitted.
|
|
|
|
|
MIRBuilder.buildCopy(Regs[0], Src);
|
|
|
|
|
}
|
|
|
|
|
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) ==
|
2020-04-17 21:36:01 +08:00
|
|
|
|
getLLTForType(*U.getType(), *DL))
|
|
|
|
|
return translateCopy(U, *U.getOperand(0), MIRBuilder);
|
|
|
|
|
|
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) {
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Op = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
|
Register Res = getOrCreateVReg(U);
|
2019-04-18 10:19:29 +08:00
|
|
|
|
MIRBuilder.buildInstr(Opcode, {Res}, {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
|
|
|
|
Value &Op0 = *U.getOperand(0);
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register 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
|
|
|
|
|
2020-01-25 11:57:49 +08:00
|
|
|
|
// Normalize Vector GEP - all scalar operands should be converted to the
|
|
|
|
|
// splat vector.
|
|
|
|
|
unsigned VectorWidth = 0;
|
|
|
|
|
if (auto *VT = dyn_cast<VectorType>(U.getType()))
|
2020-07-10 02:51:03 +08:00
|
|
|
|
VectorWidth = cast<FixedVectorType>(VT)->getNumElements();
|
2020-01-25 11:57:49 +08:00
|
|
|
|
|
2020-01-31 08:25:20 +08:00
|
|
|
|
// We might need to splat the base pointer into a vector if the offsets
|
|
|
|
|
// are vectors.
|
|
|
|
|
if (VectorWidth && !PtrTy.isVector()) {
|
|
|
|
|
BaseReg =
|
|
|
|
|
MIRBuilder.buildSplatVector(LLT::vector(VectorWidth, PtrTy), BaseReg)
|
|
|
|
|
.getReg(0);
|
[SVE] Eliminate calls to default-false VectorType::get() from CodeGen
Reviewers: efriedma, c-rhodes, david-arm, spatel, craig.topper, aqjune, paquette, arsenm, gchatelet
Reviewed By: spatel, gchatelet
Subscribers: wdng, tschuett, hiraditya, rkruppe, psnobl, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D80313
2020-06-09 01:12:08 +08:00
|
|
|
|
PtrIRTy = FixedVectorType::get(PtrIRTy, VectorWidth);
|
2020-01-31 08:25:20 +08:00
|
|
|
|
PtrTy = getLLTForType(*PtrIRTy, *DL);
|
|
|
|
|
OffsetIRTy = DL->getIntPtrType(PtrIRTy);
|
|
|
|
|
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) {
|
2019-04-15 13:04:20 +08:00
|
|
|
|
auto OffsetMIB = MIRBuilder.buildConstant({OffsetTy}, Offset);
|
[globalisel] Rename G_GEP to G_PTR_ADD
Summary:
G_GEP is rather poorly named. It's a simple pointer+scalar addition and
doesn't support any of the complexities of getelementptr. I therefore
propose that we rename it. There's a G_PTR_MASK so let's follow that
convention and go with G_PTR_ADD
Reviewers: volkan, aditya_nandakumar, bogner, rovka, arsenm
Subscribers: sdardis, jvesely, wdng, nhaehnle, hiraditya, jrtc27, atanasyan, arphaman, Petar.Avramovic, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D69734
2019-11-02 04:18:00 +08:00
|
|
|
|
BaseReg = MIRBuilder.buildPtrAdd(PtrTy, BaseReg, OffsetMIB.getReg(0))
|
|
|
|
|
.getReg(0);
|
2016-09-12 19:20:22 +08:00
|
|
|
|
Offset = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register IdxReg = getOrCreateVReg(*Idx);
|
2020-01-25 11:57:49 +08:00
|
|
|
|
LLT IdxTy = MRI->getType(IdxReg);
|
|
|
|
|
if (IdxTy != OffsetTy) {
|
|
|
|
|
if (!IdxTy.isVector() && VectorWidth) {
|
|
|
|
|
IdxReg = MIRBuilder.buildSplatVector(
|
|
|
|
|
OffsetTy.changeElementType(IdxTy), IdxReg).getReg(0);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-16 07:45:45 +08:00
|
|
|
|
IdxReg = MIRBuilder.buildSExtOrTrunc(OffsetTy, IdxReg).getReg(0);
|
2020-01-25 11:57:49 +08:00
|
|
|
|
}
|
2016-09-12 19:20:22 +08:00
|
|
|
|
|
2018-01-05 10:56:28 +08:00
|
|
|
|
// N = N + Idx * ElementSize;
|
|
|
|
|
// Avoid doing it for ElementSize of 1.
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register GepOffsetReg;
|
2018-01-05 10:56:28 +08:00
|
|
|
|
if (ElementSize != 1) {
|
2019-04-15 13:04:20 +08:00
|
|
|
|
auto ElementSizeMIB = MIRBuilder.buildConstant(
|
|
|
|
|
getLLTForType(*OffsetIRTy, *DL), ElementSize);
|
2019-08-16 07:45:45 +08:00
|
|
|
|
GepOffsetReg =
|
2020-01-30 01:34:33 +08:00
|
|
|
|
MIRBuilder.buildMul(OffsetTy, IdxReg, ElementSizeMIB).getReg(0);
|
2018-01-05 10:56:28 +08:00
|
|
|
|
} else
|
|
|
|
|
GepOffsetReg = IdxReg;
|
2016-09-12 19:20:22 +08:00
|
|
|
|
|
[globalisel] Rename G_GEP to G_PTR_ADD
Summary:
G_GEP is rather poorly named. It's a simple pointer+scalar addition and
doesn't support any of the complexities of getelementptr. I therefore
propose that we rename it. There's a G_PTR_MASK so let's follow that
convention and go with G_PTR_ADD
Reviewers: volkan, aditya_nandakumar, bogner, rovka, arsenm
Subscribers: sdardis, jvesely, wdng, nhaehnle, hiraditya, jrtc27, atanasyan, arphaman, Petar.Avramovic, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D69734
2019-11-02 04:18:00 +08:00
|
|
|
|
BaseReg = MIRBuilder.buildPtrAdd(PtrTy, BaseReg, GepOffsetReg).getReg(0);
|
2016-09-12 19:20:22 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Offset != 0) {
|
2019-04-15 13:04:20 +08:00
|
|
|
|
auto OffsetMIB =
|
2020-01-25 11:57:49 +08:00
|
|
|
|
MIRBuilder.buildConstant(OffsetTy, Offset);
|
[globalisel] Rename G_GEP to G_PTR_ADD
Summary:
G_GEP is rather poorly named. It's a simple pointer+scalar addition and
doesn't support any of the complexities of getelementptr. I therefore
propose that we rename it. There's a G_PTR_MASK so let's follow that
convention and go with G_PTR_ADD
Reviewers: volkan, aditya_nandakumar, bogner, rovka, arsenm
Subscribers: sdardis, jvesely, wdng, nhaehnle, hiraditya, jrtc27, atanasyan, arphaman, Petar.Avramovic, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D69734
2019-11-02 04:18:00 +08:00
|
|
|
|
MIRBuilder.buildPtrAdd(getOrCreateVReg(U), BaseReg, OffsetMIB.getReg(0));
|
2016-09-12 19:20:22 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildCopy(getOrCreateVReg(U), BaseReg);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-19 08:24:45 +08:00
|
|
|
|
bool IRTranslator::translateMemFunc(const CallInst &CI,
|
2017-01-31 03:33:07 +08:00
|
|
|
|
MachineIRBuilder &MIRBuilder,
|
2020-08-03 21:00:24 +08:00
|
|
|
|
unsigned Opcode) {
|
2019-06-11 05:53:56 +08:00
|
|
|
|
|
|
|
|
|
// If the source is undef, then just emit a nop.
|
2019-07-19 08:24:45 +08:00
|
|
|
|
if (isa<UndefValue>(CI.getArgOperand(1)))
|
|
|
|
|
return true;
|
2016-10-19 04:03:45 +08:00
|
|
|
|
|
2020-08-17 10:17:12 +08:00
|
|
|
|
SmallVector<Register, 3> SrcRegs;
|
|
|
|
|
|
|
|
|
|
unsigned MinPtrSize = UINT_MAX;
|
|
|
|
|
for (auto AI = CI.arg_begin(), AE = CI.arg_end(); std::next(AI) != AE; ++AI) {
|
|
|
|
|
Register SrcReg = getOrCreateVReg(**AI);
|
|
|
|
|
LLT SrcTy = MRI->getType(SrcReg);
|
|
|
|
|
if (SrcTy.isPointer())
|
|
|
|
|
MinPtrSize = std::min(SrcTy.getSizeInBits(), MinPtrSize);
|
|
|
|
|
SrcRegs.push_back(SrcReg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LLT SizeTy = LLT::scalar(MinPtrSize);
|
|
|
|
|
|
|
|
|
|
// The size operand should be the minimum of the pointer sizes.
|
|
|
|
|
Register &SizeOpReg = SrcRegs[SrcRegs.size() - 1];
|
|
|
|
|
if (MRI->getType(SizeOpReg) != SizeTy)
|
|
|
|
|
SizeOpReg = MIRBuilder.buildZExtOrTrunc(SizeTy, SizeOpReg).getReg(0);
|
|
|
|
|
|
2020-08-03 21:00:24 +08:00
|
|
|
|
auto ICall = MIRBuilder.buildInstr(Opcode);
|
2020-08-17 10:17:12 +08:00
|
|
|
|
for (Register SrcReg : SrcRegs)
|
|
|
|
|
ICall.addUse(SrcReg);
|
2019-07-19 08:24:45 +08:00
|
|
|
|
|
2020-03-31 17:43:50 +08:00
|
|
|
|
Align DstAlign;
|
|
|
|
|
Align SrcAlign;
|
2019-07-19 08:24:45 +08:00
|
|
|
|
unsigned IsVol =
|
|
|
|
|
cast<ConstantInt>(CI.getArgOperand(CI.getNumArgOperands() - 1))
|
|
|
|
|
->getZExtValue();
|
|
|
|
|
|
|
|
|
|
if (auto *MCI = dyn_cast<MemCpyInst>(&CI)) {
|
2020-03-31 17:43:50 +08:00
|
|
|
|
DstAlign = MCI->getDestAlign().valueOrOne();
|
|
|
|
|
SrcAlign = MCI->getSourceAlign().valueOrOne();
|
2019-07-19 08:24:45 +08:00
|
|
|
|
} else if (auto *MMI = dyn_cast<MemMoveInst>(&CI)) {
|
2020-03-31 17:43:50 +08:00
|
|
|
|
DstAlign = MMI->getDestAlign().valueOrOne();
|
|
|
|
|
SrcAlign = MMI->getSourceAlign().valueOrOne();
|
2019-07-19 08:24:45 +08:00
|
|
|
|
} else {
|
|
|
|
|
auto *MSI = cast<MemSetInst>(&CI);
|
2020-03-31 17:43:50 +08:00
|
|
|
|
DstAlign = MSI->getDestAlign().valueOrOne();
|
2016-10-19 04:03:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-28 13:33:21 +08:00
|
|
|
|
// We need to propagate the tail call flag from the IR inst as an argument.
|
|
|
|
|
// Otherwise, we have to pessimize and assume later that we cannot tail call
|
|
|
|
|
// any memory intrinsics.
|
|
|
|
|
ICall.addImm(CI.isTailCall() ? 1 : 0);
|
|
|
|
|
|
2019-07-19 08:24:45 +08:00
|
|
|
|
// Create mem operands to store the alignment and volatile info.
|
|
|
|
|
auto VolFlag = IsVol ? MachineMemOperand::MOVolatile : MachineMemOperand::MONone;
|
|
|
|
|
ICall.addMemOperand(MF->getMachineMemOperand(
|
|
|
|
|
MachinePointerInfo(CI.getArgOperand(0)),
|
|
|
|
|
MachineMemOperand::MOStore | VolFlag, 1, DstAlign));
|
2020-08-03 21:00:24 +08:00
|
|
|
|
if (Opcode != TargetOpcode::G_MEMSET)
|
2019-07-19 08:24:45 +08:00
|
|
|
|
ICall.addMemOperand(MF->getMachineMemOperand(
|
|
|
|
|
MachinePointerInfo(CI.getArgOperand(1)),
|
|
|
|
|
MachineMemOperand::MOLoad | VolFlag, 1, SrcAlign));
|
2016-10-19 04:03:45 +08:00
|
|
|
|
|
2019-07-19 08:24:45 +08:00
|
|
|
|
return true;
|
2016-10-19 04:03:45 +08:00
|
|
|
|
}
|
2016-09-12 19:20:22 +08:00
|
|
|
|
|
2019-06-25 00:16:12 +08:00
|
|
|
|
void IRTranslator::getStackGuard(Register DstReg,
|
2016-12-08 05:29:15 +08:00
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2017-01-28 05:31:24 +08:00
|
|
|
|
const TargetRegisterInfo *TRI = MF->getSubtarget().getRegisterInfo();
|
|
|
|
|
MRI->setRegClass(DstReg, TRI->getPointerRegClass(*MF));
|
2020-01-16 20:09:48 +08:00
|
|
|
|
auto MIB =
|
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::LOAD_STACK_GUARD, {DstReg}, {});
|
2016-11-01 02:30:59 +08:00
|
|
|
|
|
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,
|
[Alignment][NFC] Use Align version of getMachineMemOperand
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: jyknight, sdardis, nemanjai, hiraditya, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, jfb, PkmX, jocewei, Jim, lenary, s.egerton, pzheng, sameer.abuasal, apazos, luismarques, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77059
2020-03-30 22:45:57 +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) {
|
2019-06-24 23:50:29 +08:00
|
|
|
|
ArrayRef<Register> ResRegs = getOrCreateVRegs(CI);
|
2020-01-16 20:09:48 +08:00
|
|
|
|
MIRBuilder.buildInstr(
|
|
|
|
|
Op, {ResRegs[0], ResRegs[1]},
|
|
|
|
|
{getOrCreateVReg(*CI.getOperand(0)), getOrCreateVReg(*CI.getOperand(1))});
|
2016-12-09 06:44:00 +08:00
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-20 01:09:48 +08:00
|
|
|
|
bool IRTranslator::translateFixedPointIntrinsic(unsigned Op, const CallInst &CI,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
Register Dst = getOrCreateVReg(CI);
|
|
|
|
|
Register Src0 = getOrCreateVReg(*CI.getOperand(0));
|
|
|
|
|
Register Src1 = getOrCreateVReg(*CI.getOperand(1));
|
|
|
|
|
uint64_t Scale = cast<ConstantInt>(CI.getOperand(2))->getZExtValue();
|
|
|
|
|
MIRBuilder.buildInstr(Op, {Dst}, { Src0, Src1, Scale });
|
|
|
|
|
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;
|
2020-03-20 08:46:08 +08:00
|
|
|
|
case Intrinsic::bitreverse:
|
2019-09-05 01:06:53 +08:00
|
|
|
|
return TargetOpcode::G_BITREVERSE;
|
2020-03-20 08:46:08 +08:00
|
|
|
|
case Intrinsic::fshl:
|
|
|
|
|
return TargetOpcode::G_FSHL;
|
|
|
|
|
case Intrinsic::fshr:
|
|
|
|
|
return TargetOpcode::G_FSHR;
|
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-05-16 12:08:39 +08:00
|
|
|
|
case Intrinsic::copysign:
|
|
|
|
|
return TargetOpcode::G_FCOPYSIGN;
|
2019-07-11 00:31:15 +08:00
|
|
|
|
case Intrinsic::minnum:
|
|
|
|
|
return TargetOpcode::G_FMINNUM;
|
|
|
|
|
case Intrinsic::maxnum:
|
|
|
|
|
return TargetOpcode::G_FMAXNUM;
|
|
|
|
|
case Intrinsic::minimum:
|
|
|
|
|
return TargetOpcode::G_FMINIMUM;
|
|
|
|
|
case Intrinsic::maximum:
|
|
|
|
|
return TargetOpcode::G_FMAXIMUM;
|
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-04-26 00:39:28 +08:00
|
|
|
|
case Intrinsic::nearbyint:
|
|
|
|
|
return TargetOpcode::G_FNEARBYINT;
|
2019-02-13 01:38:34 +08:00
|
|
|
|
case Intrinsic::pow:
|
|
|
|
|
return TargetOpcode::G_FPOW;
|
2020-07-17 22:26:23 +08:00
|
|
|
|
case Intrinsic::powi:
|
|
|
|
|
return TargetOpcode::G_FPOWI;
|
2019-04-20 05:46:12 +08:00
|
|
|
|
case Intrinsic::rint:
|
|
|
|
|
return TargetOpcode::G_FRINT;
|
2019-02-07 01:25:54 +08:00
|
|
|
|
case Intrinsic::round:
|
|
|
|
|
return TargetOpcode::G_INTRINSIC_ROUND;
|
2020-07-19 21:56:15 +08:00
|
|
|
|
case Intrinsic::roundeven:
|
|
|
|
|
return TargetOpcode::G_INTRINSIC_ROUNDEVEN;
|
2019-02-07 01:25:54 +08:00
|
|
|
|
case Intrinsic::sin:
|
|
|
|
|
return TargetOpcode::G_FSIN;
|
|
|
|
|
case Intrinsic::sqrt:
|
|
|
|
|
return TargetOpcode::G_FSQRT;
|
|
|
|
|
case Intrinsic::trunc:
|
|
|
|
|
return TargetOpcode::G_INTRINSIC_TRUNC;
|
2020-01-05 01:46:58 +08:00
|
|
|
|
case Intrinsic::readcyclecounter:
|
|
|
|
|
return TargetOpcode::G_READCYCLECOUNTER;
|
2020-05-16 06:33:01 +08:00
|
|
|
|
case Intrinsic::ptrmask:
|
|
|
|
|
return TargetOpcode::G_PTRMASK;
|
2020-07-25 04:00:12 +08:00
|
|
|
|
case Intrinsic::lrint:
|
|
|
|
|
return TargetOpcode::G_INTRINSIC_LRINT;
|
2020-10-08 15:17:02 +08:00
|
|
|
|
// FADD/FMUL require checking the FMF, so are handled elsewhere.
|
|
|
|
|
case Intrinsic::vector_reduce_fmin:
|
|
|
|
|
return TargetOpcode::G_VECREDUCE_FMIN;
|
|
|
|
|
case Intrinsic::vector_reduce_fmax:
|
|
|
|
|
return TargetOpcode::G_VECREDUCE_FMAX;
|
|
|
|
|
case Intrinsic::vector_reduce_add:
|
|
|
|
|
return TargetOpcode::G_VECREDUCE_ADD;
|
|
|
|
|
case Intrinsic::vector_reduce_mul:
|
|
|
|
|
return TargetOpcode::G_VECREDUCE_MUL;
|
|
|
|
|
case Intrinsic::vector_reduce_and:
|
|
|
|
|
return TargetOpcode::G_VECREDUCE_AND;
|
|
|
|
|
case Intrinsic::vector_reduce_or:
|
|
|
|
|
return TargetOpcode::G_VECREDUCE_OR;
|
|
|
|
|
case Intrinsic::vector_reduce_xor:
|
|
|
|
|
return TargetOpcode::G_VECREDUCE_XOR;
|
|
|
|
|
case Intrinsic::vector_reduce_smax:
|
|
|
|
|
return TargetOpcode::G_VECREDUCE_SMAX;
|
|
|
|
|
case Intrinsic::vector_reduce_smin:
|
|
|
|
|
return TargetOpcode::G_VECREDUCE_SMIN;
|
|
|
|
|
case Intrinsic::vector_reduce_umax:
|
|
|
|
|
return TargetOpcode::G_VECREDUCE_UMAX;
|
|
|
|
|
case Intrinsic::vector_reduce_umin:
|
|
|
|
|
return TargetOpcode::G_VECREDUCE_UMIN;
|
2019-02-07 01:25:54 +08:00
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-31 23:58:56 +08:00
|
|
|
|
// TODO: Include ConstainedOps.def when all strict instructions are defined.
|
|
|
|
|
static unsigned getConstrainedOpcode(Intrinsic::ID ID) {
|
|
|
|
|
switch (ID) {
|
|
|
|
|
case Intrinsic::experimental_constrained_fadd:
|
|
|
|
|
return TargetOpcode::G_STRICT_FADD;
|
|
|
|
|
case Intrinsic::experimental_constrained_fsub:
|
|
|
|
|
return TargetOpcode::G_STRICT_FSUB;
|
|
|
|
|
case Intrinsic::experimental_constrained_fmul:
|
|
|
|
|
return TargetOpcode::G_STRICT_FMUL;
|
|
|
|
|
case Intrinsic::experimental_constrained_fdiv:
|
|
|
|
|
return TargetOpcode::G_STRICT_FDIV;
|
|
|
|
|
case Intrinsic::experimental_constrained_frem:
|
|
|
|
|
return TargetOpcode::G_STRICT_FREM;
|
|
|
|
|
case Intrinsic::experimental_constrained_fma:
|
|
|
|
|
return TargetOpcode::G_STRICT_FMA;
|
|
|
|
|
case Intrinsic::experimental_constrained_sqrt:
|
|
|
|
|
return TargetOpcode::G_STRICT_FSQRT;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IRTranslator::translateConstrainedFPIntrinsic(
|
|
|
|
|
const ConstrainedFPIntrinsic &FPI, MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
fp::ExceptionBehavior EB = FPI.getExceptionBehavior().getValue();
|
|
|
|
|
|
|
|
|
|
unsigned Opcode = getConstrainedOpcode(FPI.getIntrinsicID());
|
|
|
|
|
if (!Opcode)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
unsigned Flags = MachineInstr::copyFlagsFromInstruction(FPI);
|
|
|
|
|
if (EB == fp::ExceptionBehavior::ebIgnore)
|
|
|
|
|
Flags |= MachineInstr::NoFPExcept;
|
|
|
|
|
|
|
|
|
|
SmallVector<llvm::SrcOp, 4> VRegs;
|
|
|
|
|
VRegs.push_back(getOrCreateVReg(*FPI.getArgOperand(0)));
|
|
|
|
|
if (!FPI.isUnaryOp())
|
|
|
|
|
VRegs.push_back(getOrCreateVReg(*FPI.getArgOperand(1)));
|
|
|
|
|
if (FPI.isTernaryOp())
|
|
|
|
|
VRegs.push_back(getOrCreateVReg(*FPI.getArgOperand(2)));
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildInstr(Opcode, {getOrCreateVReg(FPI)}, VRegs, Flags);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:29:15 +08:00
|
|
|
|
bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2021-05-25 00:49:32 +08:00
|
|
|
|
if (auto *MI = dyn_cast<AnyMemIntrinsic>(&CI)) {
|
|
|
|
|
if (ORE->enabled()) {
|
|
|
|
|
const Function &F = *MI->getParent()->getParent();
|
|
|
|
|
auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
|
|
|
|
|
if (MemoryOpRemark::canHandle(MI, TLI)) {
|
|
|
|
|
MemoryOpRemark R(*ORE, "memsize", *DL, TLI);
|
|
|
|
|
R.visit(MI);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
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.
|
Add "const" in GetUnderlyingObjects. NFC
Summary:
Both the input Value pointer and the returned Value
pointers in GetUnderlyingObjects are now declared as
const.
It turned out that all current (in-tree) uses of
GetUnderlyingObjects were trivial to update, being
satisfied with have those Value pointers declared
as const. Actually, in the past several of the users
had to use const_cast, just because of ValueTracking
not providing a version of GetUnderlyingObjects with
"const" Value pointers. With this patch we get rid
of those const casts.
Reviewers: hfinkel, materi, jkorous
Reviewed By: jkorous
Subscribers: dexonsmith, jkorous, jholewinski, sdardis, eraman, hiraditya, jrtc27, atanasyan, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D61038
llvm-svn: 359072
2019-04-24 14:55:50 +08:00
|
|
|
|
SmallVector<const Value *, 4> Allocas;
|
2020-07-31 17:09:54 +08:00
|
|
|
|
getUnderlyingObjects(CI.getArgOperand(1), Allocas);
|
2019-01-29 03:22:29 +08:00
|
|
|
|
|
|
|
|
|
// Iterate over each underlying object, creating lifetime markers for each
|
|
|
|
|
// static alloca. Quit if we find a non-static alloca.
|
Add "const" in GetUnderlyingObjects. NFC
Summary:
Both the input Value pointer and the returned Value
pointers in GetUnderlyingObjects are now declared as
const.
It turned out that all current (in-tree) uses of
GetUnderlyingObjects were trivial to update, being
satisfied with have those Value pointers declared
as const. Actually, in the past several of the users
had to use const_cast, just because of ValueTracking
not providing a version of GetUnderlyingObjects with
"const" Value pointers. With this patch we get rid
of those const casts.
Reviewers: hfinkel, materi, jkorous
Reviewed By: jkorous
Subscribers: dexonsmith, jkorous, jholewinski, sdardis, eraman, hiraditya, jrtc27, atanasyan, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D61038
llvm-svn: 359072
2019-04-24 14:55:50 +08:00
|
|
|
|
for (const Value *V : Allocas) {
|
|
|
|
|
const AllocaInst *AI = dyn_cast<AllocaInst>(V);
|
2019-01-29 03:22:29 +08:00
|
|
|
|
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
|
2020-01-16 20:09:48 +08:00
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_VASTART, {}, {getOrCreateVReg(*Ptr)})
|
[Alignment][NFC] Use Align version of getMachineMemOperand
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: jyknight, sdardis, nemanjai, hiraditya, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, jfb, PkmX, jocewei, Jim, lenary, s.egerton, pzheng, sameer.abuasal, apazos, luismarques, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77059
2020-03-30 22:45:57 +08:00
|
|
|
|
.addMemOperand(MF->getMachineMemOperand(MachinePointerInfo(Ptr),
|
|
|
|
|
MachineMemOperand::MOStore,
|
|
|
|
|
ListSize, Align(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");
|
2021-05-20 23:33:38 +08:00
|
|
|
|
if (!V || DI.hasArgList()) {
|
|
|
|
|
// DI cannot produce a valid DBG_VALUE, so produce an undef DBG_VALUE to
|
|
|
|
|
// terminate any prior location.
|
2020-02-06 01:27:44 +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 {
|
2019-08-21 00:28:37 +08:00
|
|
|
|
for (Register Reg : getOrCreateVRegs(*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 place, but it seems
|
|
|
|
|
// pretty baked in right now.
|
|
|
|
|
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);
|
[GlobalISel] Add generic opcodes for saturating add/subtract
Summary:
Add new generic MIR opcodes G_SADDSAT etc. Add support in IRTranslator
for translating the saturating add/subtract intrinsics to the new
opcodes.
Reviewers: aemerson, dsanders, paquette, arsenm
Subscribers: jvesely, wdng, nhaehnle, rovka, hiraditya, volkan, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D76600
2020-02-24 19:13:05 +08:00
|
|
|
|
case Intrinsic::uadd_sat:
|
|
|
|
|
return translateBinaryOp(TargetOpcode::G_UADDSAT, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::sadd_sat:
|
|
|
|
|
return translateBinaryOp(TargetOpcode::G_SADDSAT, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::usub_sat:
|
|
|
|
|
return translateBinaryOp(TargetOpcode::G_USUBSAT, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::ssub_sat:
|
|
|
|
|
return translateBinaryOp(TargetOpcode::G_SSUBSAT, CI, MIRBuilder);
|
[Intrinsic] Add sshl.sat/ushl.sat, saturated shift intrinsics.
Summary:
This patch adds two intrinsics, llvm.sshl.sat and llvm.ushl.sat,
which perform signed and unsigned saturating left shift,
respectively.
These are useful for implementing the Embedded-C fixed point
support in Clang, originally discussed in
http://lists.llvm.org/pipermail/llvm-dev/2018-August/125433.html
and
http://lists.llvm.org/pipermail/cfe-dev/2018-May/058019.html
Reviewers: leonardchan, craig.topper, bjope, jdoerfert
Subscribers: hiraditya, jdoerfert, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D83216
2020-07-16 23:02:04 +08:00
|
|
|
|
case Intrinsic::ushl_sat:
|
|
|
|
|
return translateBinaryOp(TargetOpcode::G_USHLSAT, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::sshl_sat:
|
|
|
|
|
return translateBinaryOp(TargetOpcode::G_SSHLSAT, CI, MIRBuilder);
|
2020-07-19 23:06:17 +08:00
|
|
|
|
case Intrinsic::umin:
|
|
|
|
|
return translateBinaryOp(TargetOpcode::G_UMIN, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::umax:
|
|
|
|
|
return translateBinaryOp(TargetOpcode::G_UMAX, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::smin:
|
|
|
|
|
return translateBinaryOp(TargetOpcode::G_SMIN, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::smax:
|
|
|
|
|
return translateBinaryOp(TargetOpcode::G_SMAX, CI, MIRBuilder);
|
2020-08-11 17:50:58 +08:00
|
|
|
|
case Intrinsic::abs:
|
|
|
|
|
// TODO: Preserve "int min is poison" arg in GMIR?
|
|
|
|
|
return translateUnaryOp(TargetOpcode::G_ABS, CI, MIRBuilder);
|
2020-07-20 01:09:48 +08:00
|
|
|
|
case Intrinsic::smul_fix:
|
|
|
|
|
return translateFixedPointIntrinsic(TargetOpcode::G_SMULFIX, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::umul_fix:
|
|
|
|
|
return translateFixedPointIntrinsic(TargetOpcode::G_UMULFIX, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::smul_fix_sat:
|
|
|
|
|
return translateFixedPointIntrinsic(TargetOpcode::G_SMULFIXSAT, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::umul_fix_sat:
|
|
|
|
|
return translateFixedPointIntrinsic(TargetOpcode::G_UMULFIXSAT, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::sdiv_fix:
|
|
|
|
|
return translateFixedPointIntrinsic(TargetOpcode::G_SDIVFIX, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::udiv_fix:
|
|
|
|
|
return translateFixedPointIntrinsic(TargetOpcode::G_UDIVFIX, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::sdiv_fix_sat:
|
|
|
|
|
return translateFixedPointIntrinsic(TargetOpcode::G_SDIVFIXSAT, CI, MIRBuilder);
|
|
|
|
|
case Intrinsic::udiv_fix_sat:
|
|
|
|
|
return translateFixedPointIntrinsic(TargetOpcode::G_UDIVFIXSAT, CI, MIRBuilder);
|
2018-02-13 08:47:46 +08:00
|
|
|
|
case Intrinsic::fmuladd: {
|
|
|
|
|
const TargetMachine &TM = MF->getTarget();
|
|
|
|
|
const TargetLowering &TLI = *MF->getSubtarget().getTargetLowering();
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Dst = getOrCreateVReg(CI);
|
|
|
|
|
Register Op0 = getOrCreateVReg(*CI.getArgOperand(0));
|
|
|
|
|
Register Op1 = getOrCreateVReg(*CI.getArgOperand(1));
|
|
|
|
|
Register Op2 = getOrCreateVReg(*CI.getArgOperand(2));
|
2018-02-13 08:47:46 +08:00
|
|
|
|
if (TM.Options.AllowFPOpFusion != FPOpFusion::Strict &&
|
2019-10-29 08:38:44 +08:00
|
|
|
|
TLI.isFMAFasterThanFMulAndFAdd(*MF,
|
|
|
|
|
TLI.getValueType(*DL, CI.getType()))) {
|
2018-02-13 08:47:46 +08:00
|
|
|
|
// TODO: Revisit this to see if we should move this part of the
|
|
|
|
|
// lowering to the combiner.
|
2020-01-16 20:09:48 +08:00
|
|
|
|
MIRBuilder.buildFMA(Dst, Op0, Op1, Op2,
|
|
|
|
|
MachineInstr::copyFlagsFromInstruction(CI));
|
2018-02-13 08:47:46 +08:00
|
|
|
|
} else {
|
|
|
|
|
LLT Ty = getLLTForType(*CI.getType(), *DL);
|
2020-01-16 20:09:48 +08:00
|
|
|
|
auto FMul = MIRBuilder.buildFMul(
|
|
|
|
|
Ty, Op0, Op1, MachineInstr::copyFlagsFromInstruction(CI));
|
|
|
|
|
MIRBuilder.buildFAdd(Dst, FMul, Op2,
|
|
|
|
|
MachineInstr::copyFlagsFromInstruction(CI));
|
2018-02-13 08:47:46 +08:00
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-07-26 04:58:15 +08:00
|
|
|
|
case Intrinsic::convert_from_fp16:
|
|
|
|
|
// FIXME: This intrinsic should probably be removed from the IR.
|
|
|
|
|
MIRBuilder.buildFPExt(getOrCreateVReg(CI),
|
|
|
|
|
getOrCreateVReg(*CI.getArgOperand(0)),
|
|
|
|
|
MachineInstr::copyFlagsFromInstruction(CI));
|
|
|
|
|
return true;
|
|
|
|
|
case Intrinsic::convert_to_fp16:
|
|
|
|
|
// FIXME: This intrinsic should probably be removed from the IR.
|
|
|
|
|
MIRBuilder.buildFPTrunc(getOrCreateVReg(CI),
|
|
|
|
|
getOrCreateVReg(*CI.getArgOperand(0)),
|
|
|
|
|
MachineInstr::copyFlagsFromInstruction(CI));
|
|
|
|
|
return true;
|
2016-10-19 04:03:45 +08:00
|
|
|
|
case Intrinsic::memcpy:
|
2020-08-03 21:00:24 +08:00
|
|
|
|
return translateMemFunc(CI, MIRBuilder, TargetOpcode::G_MEMCPY);
|
2017-01-31 03:33:07 +08:00
|
|
|
|
case Intrinsic::memmove:
|
2020-08-03 21:00:24 +08:00
|
|
|
|
return translateMemFunc(CI, MIRBuilder, TargetOpcode::G_MEMMOVE);
|
2017-01-31 03:33:07 +08:00
|
|
|
|
case Intrinsic::memset:
|
2020-08-03 21:00:24 +08:00
|
|
|
|
return translateMemFunc(CI, MIRBuilder, TargetOpcode::G_MEMSET);
|
2016-11-10 06:39:54 +08:00
|
|
|
|
case Intrinsic::eh_typeid_for: {
|
|
|
|
|
GlobalValue *GV = ExtractTypeInfo(CI.getArgOperand(0));
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register 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;
|
|
|
|
|
}
|
2019-10-15 00:15:14 +08:00
|
|
|
|
case Intrinsic::objectsize:
|
|
|
|
|
llvm_unreachable("llvm.objectsize.* should have been lowered already");
|
2016-10-19 04:03:51 +08:00
|
|
|
|
|
2018-11-07 23:24:12 +08:00
|
|
|
|
case Intrinsic::is_constant:
|
2019-10-15 00:15:14 +08:00
|
|
|
|
llvm_unreachable("llvm.is.constant.* should have been lowered already");
|
|
|
|
|
|
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);
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register 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,
|
2020-03-31 17:43:50 +08:00
|
|
|
|
PtrTy.getSizeInBits() / 8, Align(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.
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Reg = getOrCreateVReg(CI);
|
|
|
|
|
Register StackPtr = MF->getSubtarget()
|
2019-04-03 06:46:31 +08:00
|
|
|
|
.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.
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Reg = getOrCreateVReg(*CI.getArgOperand(0));
|
|
|
|
|
Register StackPtr = MF->getSubtarget()
|
2019-04-03 06:46:31 +08:00
|
|
|
|
.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;
|
2020-01-16 20:09:48 +08:00
|
|
|
|
MIRBuilder.buildInstr(Opcode, {getOrCreateVReg(CI)},
|
|
|
|
|
{getOrCreateVReg(*CI.getArgOperand(0))});
|
2018-08-04 09:22:12 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-10-06 05:02:46 +08:00
|
|
|
|
case Intrinsic::invariant_start: {
|
|
|
|
|
LLT PtrTy = getLLTForType(*CI.getArgOperand(0)->getType(), *DL);
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Undef = MRI->createGenericVirtualRegister(PtrTy);
|
2018-10-06 05:02:46 +08:00
|
|
|
|
MIRBuilder.buildUndef(Undef);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case Intrinsic::invariant_end:
|
|
|
|
|
return true;
|
2020-07-29 20:55:02 +08:00
|
|
|
|
case Intrinsic::expect:
|
|
|
|
|
case Intrinsic::annotation:
|
|
|
|
|
case Intrinsic::ptr_annotation:
|
|
|
|
|
case Intrinsic::launder_invariant_group:
|
|
|
|
|
case Intrinsic::strip_invariant_group: {
|
|
|
|
|
// Drop the intrinsic, but forward the value.
|
|
|
|
|
MIRBuilder.buildCopy(getOrCreateVReg(CI),
|
|
|
|
|
getOrCreateVReg(*CI.getArgOperand(0)));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
[GlobalISel] IRTranslator: Translate the intrinsics ignored by CodeGen
Summary:
Translate `llvm.assume`, `llvm.var.annotation` and `llvm.sideeffect` to nothing
as they have no effect on CodeGen.
Reviewers: qcolombet, aditya_nandakumar, dsanders, paquette, aemerson, arsenm
Reviewed By: arsenm
Subscribers: hiraditya, wdng, rovka, kristof.beyls, javed.absar, Petar.Avramovic, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63022
llvm-svn: 362834
2019-06-08 04:19:27 +08:00
|
|
|
|
case Intrinsic::assume:
|
2021-01-27 04:54:41 +08:00
|
|
|
|
case Intrinsic::experimental_noalias_scope_decl:
|
[GlobalISel] IRTranslator: Translate the intrinsics ignored by CodeGen
Summary:
Translate `llvm.assume`, `llvm.var.annotation` and `llvm.sideeffect` to nothing
as they have no effect on CodeGen.
Reviewers: qcolombet, aditya_nandakumar, dsanders, paquette, aemerson, arsenm
Reviewed By: arsenm
Subscribers: hiraditya, wdng, rovka, kristof.beyls, javed.absar, Petar.Avramovic, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63022
llvm-svn: 362834
2019-06-08 04:19:27 +08:00
|
|
|
|
case Intrinsic::var_annotation:
|
|
|
|
|
case Intrinsic::sideeffect:
|
|
|
|
|
// Discard annotate attributes, assumptions, and artificial side-effects.
|
|
|
|
|
return true;
|
2020-07-15 16:11:36 +08:00
|
|
|
|
case Intrinsic::read_volatile_register:
|
2019-12-28 08:26:51 +08:00
|
|
|
|
case Intrinsic::read_register: {
|
|
|
|
|
Value *Arg = CI.getArgOperand(0);
|
2020-01-16 20:09:48 +08:00
|
|
|
|
MIRBuilder
|
|
|
|
|
.buildInstr(TargetOpcode::G_READ_REGISTER, {getOrCreateVReg(CI)}, {})
|
|
|
|
|
.addMetadata(cast<MDNode>(cast<MetadataAsValue>(Arg)->getMetadata()));
|
2019-12-28 08:26:51 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-01-13 02:29:44 +08:00
|
|
|
|
case Intrinsic::write_register: {
|
|
|
|
|
Value *Arg = CI.getArgOperand(0);
|
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_WRITE_REGISTER)
|
|
|
|
|
.addMetadata(cast<MDNode>(cast<MetadataAsValue>(Arg)->getMetadata()))
|
|
|
|
|
.addUse(getOrCreateVReg(*CI.getArgOperand(1)));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-07-29 21:48:26 +08:00
|
|
|
|
case Intrinsic::localescape: {
|
|
|
|
|
MachineBasicBlock &EntryMBB = MF->front();
|
|
|
|
|
StringRef EscapedName = GlobalValue::dropLLVMManglingEscape(MF->getName());
|
|
|
|
|
|
|
|
|
|
// Directly emit some LOCAL_ESCAPE machine instrs. Label assignment emission
|
|
|
|
|
// is the same on all targets.
|
|
|
|
|
for (unsigned Idx = 0, E = CI.getNumArgOperands(); Idx < E; ++Idx) {
|
|
|
|
|
Value *Arg = CI.getArgOperand(Idx)->stripPointerCasts();
|
|
|
|
|
if (isa<ConstantPointerNull>(Arg))
|
|
|
|
|
continue; // Skip null pointers. They represent a hole in index space.
|
|
|
|
|
|
|
|
|
|
int FI = getOrCreateFrameIndex(*cast<AllocaInst>(Arg));
|
|
|
|
|
MCSymbol *FrameAllocSym =
|
|
|
|
|
MF->getMMI().getContext().getOrCreateFrameAllocSymbol(EscapedName,
|
|
|
|
|
Idx);
|
|
|
|
|
|
|
|
|
|
// This should be inserted at the start of the entry block.
|
|
|
|
|
auto LocalEscape =
|
|
|
|
|
MIRBuilder.buildInstrNoInsert(TargetOpcode::LOCAL_ESCAPE)
|
|
|
|
|
.addSym(FrameAllocSym)
|
|
|
|
|
.addFrameIndex(FI);
|
|
|
|
|
|
|
|
|
|
EntryMBB.insert(EntryMBB.begin(), LocalEscape);
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-08 15:17:02 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
case Intrinsic::vector_reduce_fadd:
|
|
|
|
|
case Intrinsic::vector_reduce_fmul: {
|
|
|
|
|
// Need to check for the reassoc flag to decide whether we want a
|
|
|
|
|
// sequential reduction opcode or not.
|
|
|
|
|
Register Dst = getOrCreateVReg(CI);
|
|
|
|
|
Register ScalarSrc = getOrCreateVReg(*CI.getArgOperand(0));
|
|
|
|
|
Register VecSrc = getOrCreateVReg(*CI.getArgOperand(1));
|
|
|
|
|
unsigned Opc = 0;
|
|
|
|
|
if (!CI.hasAllowReassoc()) {
|
|
|
|
|
// The sequential ordering case.
|
|
|
|
|
Opc = ID == Intrinsic::vector_reduce_fadd
|
|
|
|
|
? TargetOpcode::G_VECREDUCE_SEQ_FADD
|
|
|
|
|
: TargetOpcode::G_VECREDUCE_SEQ_FMUL;
|
|
|
|
|
MIRBuilder.buildInstr(Opc, {Dst}, {ScalarSrc, VecSrc},
|
|
|
|
|
MachineInstr::copyFlagsFromInstruction(CI));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// We split the operation into a separate G_FADD/G_FMUL + the reduce,
|
|
|
|
|
// since the associativity doesn't matter.
|
|
|
|
|
unsigned ScalarOpc;
|
|
|
|
|
if (ID == Intrinsic::vector_reduce_fadd) {
|
|
|
|
|
Opc = TargetOpcode::G_VECREDUCE_FADD;
|
|
|
|
|
ScalarOpc = TargetOpcode::G_FADD;
|
|
|
|
|
} else {
|
|
|
|
|
Opc = TargetOpcode::G_VECREDUCE_FMUL;
|
|
|
|
|
ScalarOpc = TargetOpcode::G_FMUL;
|
|
|
|
|
}
|
|
|
|
|
LLT DstTy = MRI->getType(Dst);
|
|
|
|
|
auto Rdx = MIRBuilder.buildInstr(
|
|
|
|
|
Opc, {DstTy}, {VecSrc}, MachineInstr::copyFlagsFromInstruction(CI));
|
|
|
|
|
MIRBuilder.buildInstr(ScalarOpc, {Dst}, {ScalarSrc, Rdx},
|
|
|
|
|
MachineInstr::copyFlagsFromInstruction(CI));
|
|
|
|
|
|
2020-07-29 21:48:26 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-05-31 23:58:56 +08:00
|
|
|
|
#define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC) \
|
|
|
|
|
case Intrinsic::INTRINSIC:
|
|
|
|
|
#include "llvm/IR/ConstrainedOps.def"
|
|
|
|
|
return translateConstrainedFPIntrinsic(cast<ConstrainedFPIntrinsic>(CI),
|
|
|
|
|
MIRBuilder);
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
[GlobalISel] Introduce InlineAsmLowering class
Summary:
Similar to the CallLowering class used for lowering LLVM IR calls to MIR calls,
we introduce a separate class for lowering LLVM IR inline asm to MIR INLINEASM.
There is no functional change yet, all existing tests should pass.
Reviewers: arsenm, dsanders, aemerson, volkan, t.p.northover, paquette
Reviewed By: aemerson
Subscribers: gargaroff, wdng, mgorny, rovka, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78316
2020-04-08 20:40:43 +08:00
|
|
|
|
bool IRTranslator::translateInlineAsm(const CallBase &CB,
|
2017-03-10 07:36:26 +08:00
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
|
[GlobalISel] Introduce InlineAsmLowering class
Summary:
Similar to the CallLowering class used for lowering LLVM IR calls to MIR calls,
we introduce a separate class for lowering LLVM IR inline asm to MIR INLINEASM.
There is no functional change yet, all existing tests should pass.
Reviewers: arsenm, dsanders, aemerson, volkan, t.p.northover, paquette
Reviewed By: aemerson
Subscribers: gargaroff, wdng, mgorny, rovka, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78316
2020-04-08 20:40:43 +08:00
|
|
|
|
const InlineAsmLowering *ALI = MF->getSubtarget().getInlineAsmLowering();
|
2020-02-07 17:07:57 +08:00
|
|
|
|
|
[GlobalISel] Introduce InlineAsmLowering class
Summary:
Similar to the CallLowering class used for lowering LLVM IR calls to MIR calls,
we introduce a separate class for lowering LLVM IR inline asm to MIR INLINEASM.
There is no functional change yet, all existing tests should pass.
Reviewers: arsenm, dsanders, aemerson, volkan, t.p.northover, paquette
Reviewed By: aemerson
Subscribers: gargaroff, wdng, mgorny, rovka, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78316
2020-04-08 20:40:43 +08:00
|
|
|
|
if (!ALI) {
|
|
|
|
|
LLVM_DEBUG(
|
|
|
|
|
dbgs() << "Inline asm lowering is not supported for this target yet\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-03-10 07:36:26 +08:00
|
|
|
|
|
2020-04-09 02:04:13 +08:00
|
|
|
|
return ALI->lowerInlineAsm(
|
|
|
|
|
MIRBuilder, CB, [&](const Value &Val) { return getOrCreateVRegs(Val); });
|
2017-03-10 07:36:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
2020-04-14 01:17:29 +08:00
|
|
|
|
bool IRTranslator::translateCallBase(const CallBase &CB,
|
2019-08-07 20:43:53 +08:00
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
2020-04-14 01:17:29 +08:00
|
|
|
|
ArrayRef<Register> Res = getOrCreateVRegs(CB);
|
2019-08-07 20:43:53 +08:00
|
|
|
|
|
|
|
|
|
SmallVector<ArrayRef<Register>, 8> Args;
|
|
|
|
|
Register SwiftInVReg = 0;
|
|
|
|
|
Register SwiftErrorVReg = 0;
|
2020-04-14 01:17:29 +08:00
|
|
|
|
for (auto &Arg : CB.args()) {
|
2019-08-07 20:43:53 +08:00
|
|
|
|
if (CLI->supportSwiftError() && isSwiftError(Arg)) {
|
|
|
|
|
assert(SwiftInVReg == 0 && "Expected only one swift error argument");
|
|
|
|
|
LLT Ty = getLLTForType(*Arg->getType(), *DL);
|
|
|
|
|
SwiftInVReg = MRI->createGenericVirtualRegister(Ty);
|
|
|
|
|
MIRBuilder.buildCopy(SwiftInVReg, SwiftError.getOrCreateVRegUseAt(
|
2020-04-14 01:17:29 +08:00
|
|
|
|
&CB, &MIRBuilder.getMBB(), Arg));
|
2019-08-07 20:43:53 +08:00
|
|
|
|
Args.emplace_back(makeArrayRef(SwiftInVReg));
|
|
|
|
|
SwiftErrorVReg =
|
2020-04-14 01:17:29 +08:00
|
|
|
|
SwiftError.getOrCreateVRegDefAt(&CB, &MIRBuilder.getMBB(), Arg);
|
2019-08-07 20:43:53 +08:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Args.push_back(getOrCreateVRegs(*Arg));
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-25 00:49:32 +08:00
|
|
|
|
if (auto *CI = dyn_cast<CallInst>(&CB)) {
|
|
|
|
|
if (ORE->enabled()) {
|
|
|
|
|
const Function &F = *CI->getParent()->getParent();
|
|
|
|
|
auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F);
|
|
|
|
|
if (MemoryOpRemark::canHandle(CI, TLI)) {
|
|
|
|
|
MemoryOpRemark R(*ORE, "memsize", *DL, TLI);
|
|
|
|
|
R.visit(CI);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-21 07:52:07 +08:00
|
|
|
|
// We don't set HasCalls on MFI here yet because call lowering may decide to
|
|
|
|
|
// optimize into tail calls. Instead, we defer that to selection where a final
|
|
|
|
|
// scan is done to check if any instructions are calls.
|
2019-08-07 20:43:53 +08:00
|
|
|
|
bool Success =
|
2020-04-14 01:17:29 +08:00
|
|
|
|
CLI->lowerCall(MIRBuilder, CB, Res, Args, SwiftErrorVReg,
|
2020-04-28 11:15:59 +08:00
|
|
|
|
[&]() { return getOrCreateVReg(*CB.getCalledOperand()); });
|
2019-08-07 20:43:53 +08:00
|
|
|
|
|
2019-09-11 07:34:45 +08:00
|
|
|
|
// Check if we just inserted a tail call.
|
|
|
|
|
if (Success) {
|
|
|
|
|
assert(!HasTailCall && "Can't tail call return twice from block?");
|
|
|
|
|
const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
|
|
|
|
|
HasTailCall = TII->isTailCall(*std::prev(MIRBuilder.getInsertPt()));
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-07 20:43:53 +08:00
|
|
|
|
return Success;
|
|
|
|
|
}
|
|
|
|
|
|
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.
|
2019-12-19 20:00:44 +08:00
|
|
|
|
if (F && (F->hasDLLImportStorageClass() ||
|
|
|
|
|
(MF->getTarget().getTargetTriple().isOSWindows() &&
|
|
|
|
|
F->hasExternalWeakLinkage())))
|
2018-01-31 03:50:58 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
Add Windows Control Flow Guard checks (/guard:cf).
Summary:
A new function pass (Transforms/CFGuard/CFGuard.cpp) inserts CFGuard checks on
indirect function calls, using either the check mechanism (X86, ARM, AArch64) or
or the dispatch mechanism (X86-64). The check mechanism requires a new calling
convention for the supported targets. The dispatch mechanism adds the target as
an operand bundle, which is processed by SelectionDAG. Another pass
(CodeGen/CFGuardLongjmp.cpp) identifies and emits valid longjmp targets, as
required by /guard:cf. This feature is enabled using the `cfguard` CC1 option.
Reviewers: thakis, rnk, theraven, pcc
Subscribers: ychen, hans, metalcanine, dmajor, tomrittervg, alex, mehdi_amini, mgorny, javed.absar, kristof.beyls, hiraditya, steven_wu, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D65761
2019-10-28 21:22:19 +08:00
|
|
|
|
// FIXME: support control flow guard targets.
|
|
|
|
|
if (CI.countOperandBundlesOfType(LLVMContext::OB_cfguardtarget))
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-07 20:43:53 +08:00
|
|
|
|
if (!F || !F->isIntrinsic() || ID == Intrinsic::not_intrinsic)
|
2020-04-14 01:17:29 +08:00
|
|
|
|
return translateCallBase(CI, MIRBuilder);
|
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-06-24 23:50:29 +08:00
|
|
|
|
ArrayRef<Register> ResultRegs;
|
2019-03-14 22:18:56 +08:00
|
|
|
|
if (!CI.getType()->isVoidTy())
|
|
|
|
|
ResultRegs = getOrCreateVRegs(CI);
|
|
|
|
|
|
2019-06-18 01:01:35 +08:00
|
|
|
|
// Ignore the callsite attributes. Backend code is most likely not expecting
|
|
|
|
|
// an intrinsic to sometimes have side effects and sometimes not.
|
2016-07-30 06:32:36 +08:00
|
|
|
|
MachineInstrBuilder MIB =
|
2019-06-18 01:01:35 +08:00
|
|
|
|
MIRBuilder.buildIntrinsic(ID, ResultRegs, !F->doesNotAccessMemory());
|
2019-04-19 02:48:57 +08:00
|
|
|
|
if (isa<FPMathOperator>(CI))
|
|
|
|
|
MIB->copyIRFlags(CI);
|
2016-07-30 06:32:36 +08:00
|
|
|
|
|
2019-09-20 00:26:14 +08:00
|
|
|
|
for (auto &Arg : enumerate(CI.arg_operands())) {
|
|
|
|
|
// If this is required to be an immediate, don't materialize it in a
|
|
|
|
|
// register.
|
|
|
|
|
if (CI.paramHasAttr(Arg.index(), Attribute::ImmArg)) {
|
|
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(Arg.value())) {
|
|
|
|
|
// imm arguments are more convenient than cimm (and realistically
|
|
|
|
|
// probably sufficient), so use them.
|
|
|
|
|
assert(CI->getBitWidth() <= 64 &&
|
|
|
|
|
"large intrinsic immediates not handled");
|
|
|
|
|
MIB.addImm(CI->getSExtValue());
|
|
|
|
|
} else {
|
|
|
|
|
MIB.addFPImm(cast<ConstantFP>(Arg.value()));
|
|
|
|
|
}
|
2020-07-22 07:29:37 +08:00
|
|
|
|
} else if (auto MD = dyn_cast<MetadataAsValue>(Arg.value())) {
|
|
|
|
|
auto *MDN = dyn_cast<MDNode>(MD->getMetadata());
|
|
|
|
|
if (!MDN) // This was probably an MDString.
|
|
|
|
|
return false;
|
|
|
|
|
MIB.addMetadata(MDN);
|
2019-09-20 00:26:14 +08:00
|
|
|
|
} else {
|
|
|
|
|
ArrayRef<Register> VRegs = getOrCreateVRegs(*Arg.value());
|
|
|
|
|
if (VRegs.size() > 1)
|
|
|
|
|
return false;
|
|
|
|
|
MIB.addUse(VRegs[0]);
|
|
|
|
|
}
|
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)) {
|
[Alignment][NFC] Use Align version of getMachineMemOperand
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: jyknight, sdardis, nemanjai, hiraditya, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, jfb, PkmX, jocewei, Jim, lenary, s.egerton, pzheng, sameer.abuasal, apazos, luismarques, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77059
2020-03-30 22:45:57 +08:00
|
|
|
|
Align Alignment = Info.align.getValueOr(
|
|
|
|
|
DL->getABITypeAlign(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();
|
[Alignment][NFC] Use Align version of getMachineMemOperand
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: jyknight, sdardis, nemanjai, hiraditya, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, jfb, PkmX, jocewei, Jim, lenary, s.egerton, pzheng, sameer.abuasal, apazos, luismarques, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77059
2020-03-30 22:45:57 +08:00
|
|
|
|
MIB.addMemOperand(MF->getMachineMemOperand(MachinePointerInfo(Info.ptrVal),
|
|
|
|
|
Info.flags, Size, Alignment));
|
2017-06-06 06:17:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
2016-07-30 06:32:36 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-15 07:25:35 +08:00
|
|
|
|
bool IRTranslator::findUnwindDestinations(
|
|
|
|
|
const BasicBlock *EHPadBB,
|
|
|
|
|
BranchProbability Prob,
|
|
|
|
|
SmallVectorImpl<std::pair<MachineBasicBlock *, BranchProbability>>
|
|
|
|
|
&UnwindDests) {
|
|
|
|
|
EHPersonality Personality = classifyEHPersonality(
|
|
|
|
|
EHPadBB->getParent()->getFunction().getPersonalityFn());
|
|
|
|
|
bool IsMSVCCXX = Personality == EHPersonality::MSVC_CXX;
|
|
|
|
|
bool IsCoreCLR = Personality == EHPersonality::CoreCLR;
|
|
|
|
|
bool IsWasmCXX = Personality == EHPersonality::Wasm_CXX;
|
|
|
|
|
bool IsSEH = isAsynchronousEHPersonality(Personality);
|
|
|
|
|
|
|
|
|
|
if (IsWasmCXX) {
|
|
|
|
|
// Ignore this for now.
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (EHPadBB) {
|
|
|
|
|
const Instruction *Pad = EHPadBB->getFirstNonPHI();
|
|
|
|
|
BasicBlock *NewEHPadBB = nullptr;
|
|
|
|
|
if (isa<LandingPadInst>(Pad)) {
|
|
|
|
|
// Stop on landingpads. They are not funclets.
|
|
|
|
|
UnwindDests.emplace_back(&getMBB(*EHPadBB), Prob);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (isa<CleanupPadInst>(Pad)) {
|
|
|
|
|
// Stop on cleanup pads. Cleanups are always funclet entries for all known
|
|
|
|
|
// personalities.
|
|
|
|
|
UnwindDests.emplace_back(&getMBB(*EHPadBB), Prob);
|
|
|
|
|
UnwindDests.back().first->setIsEHScopeEntry();
|
|
|
|
|
UnwindDests.back().first->setIsEHFuncletEntry();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Pad)) {
|
|
|
|
|
// Add the catchpad handlers to the possible destinations.
|
|
|
|
|
for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) {
|
|
|
|
|
UnwindDests.emplace_back(&getMBB(*CatchPadBB), Prob);
|
|
|
|
|
// For MSVC++ and the CLR, catchblocks are funclets and need prologues.
|
|
|
|
|
if (IsMSVCCXX || IsCoreCLR)
|
|
|
|
|
UnwindDests.back().first->setIsEHFuncletEntry();
|
|
|
|
|
if (!IsSEH)
|
|
|
|
|
UnwindDests.back().first->setIsEHScopeEntry();
|
|
|
|
|
}
|
|
|
|
|
NewEHPadBB = CatchSwitch->getUnwindDest();
|
|
|
|
|
} else {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BranchProbabilityInfo *BPI = FuncInfo.BPI;
|
|
|
|
|
if (BPI && NewEHPadBB)
|
|
|
|
|
Prob *= BPI->getEdgeProbability(EHPadBB, NewEHPadBB);
|
|
|
|
|
EHPadBB = NewEHPadBB;
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
2020-04-28 11:15:59 +08:00
|
|
|
|
const Function *Fn = I.getCalledFunction();
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
Add Windows Control Flow Guard checks (/guard:cf).
Summary:
A new function pass (Transforms/CFGuard/CFGuard.cpp) inserts CFGuard checks on
indirect function calls, using either the check mechanism (X86, ARM, AArch64) or
or the dispatch mechanism (X86-64). The check mechanism requires a new calling
convention for the supported targets. The dispatch mechanism adds the target as
an operand bundle, which is processed by SelectionDAG. Another pass
(CodeGen/CFGuardLongjmp.cpp) identifies and emits valid longjmp targets, as
required by /guard:cf. This feature is enabled using the `cfguard` CC1 option.
Reviewers: thakis, rnk, theraven, pcc
Subscribers: ychen, hans, metalcanine, dmajor, tomrittervg, alex, mehdi_amini, mgorny, javed.absar, kristof.beyls, hiraditya, steven_wu, dexonsmith, cfe-commits, llvm-commits
Tags: #clang, #llvm
Differential Revision: https://reviews.llvm.org/D65761
2019-10-28 21:22:19 +08:00
|
|
|
|
// FIXME: support control flow guard targets.
|
|
|
|
|
if (I.countOperandBundlesOfType(LLVMContext::OB_cfguardtarget))
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-11-10 06:39:54 +08:00
|
|
|
|
// FIXME: support Windows exception handling.
|
2020-08-18 16:32:44 +08:00
|
|
|
|
if (!isa<LandingPadInst>(EHPadBB->getFirstNonPHI()))
|
2016-11-10 06:39:54 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
2021-05-14 02:05:11 +08:00
|
|
|
|
bool LowerInlineAsm = false;
|
|
|
|
|
if (I.isInlineAsm()) {
|
|
|
|
|
const InlineAsm *IA = cast<InlineAsm>(I.getCalledOperand());
|
|
|
|
|
if (!IA->canThrow()) {
|
|
|
|
|
// Fast path without emitting EH_LABELs.
|
|
|
|
|
|
|
|
|
|
if (!translateInlineAsm(I, MIRBuilder))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
MachineBasicBlock *InvokeMBB = &MIRBuilder.getMBB(),
|
|
|
|
|
*ReturnMBB = &getMBB(*ReturnBB);
|
|
|
|
|
|
|
|
|
|
// Update successor info.
|
|
|
|
|
addSuccessorWithProb(InvokeMBB, ReturnMBB, BranchProbability::getOne());
|
|
|
|
|
|
|
|
|
|
MIRBuilder.buildBr(*ReturnMBB);
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
LowerInlineAsm = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
|
|
2021-05-14 02:05:11 +08:00
|
|
|
|
if (LowerInlineAsm) {
|
|
|
|
|
if (!translateInlineAsm(I, MIRBuilder))
|
|
|
|
|
return false;
|
|
|
|
|
} else if (!translateCallBase(I, MIRBuilder))
|
2017-03-10 08:25:35 +08:00
|
|
|
|
return false;
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
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);
|
|
|
|
|
|
2020-12-15 07:25:35 +08:00
|
|
|
|
SmallVector<std::pair<MachineBasicBlock *, BranchProbability>, 1> UnwindDests;
|
|
|
|
|
BranchProbabilityInfo *BPI = FuncInfo.BPI;
|
|
|
|
|
MachineBasicBlock *InvokeMBB = &MIRBuilder.getMBB();
|
|
|
|
|
BranchProbability EHPadBBProb =
|
|
|
|
|
BPI ? BPI->getEdgeProbability(InvokeMBB->getBasicBlock(), EHPadBB)
|
|
|
|
|
: BranchProbability::getZero();
|
|
|
|
|
|
|
|
|
|
if (!findUnwindDestinations(EHPadBB, EHPadBBProb, UnwindDests))
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-03-16 02:22:33 +08:00
|
|
|
|
MachineBasicBlock &EHPadMBB = getMBB(*EHPadBB),
|
|
|
|
|
&ReturnMBB = getMBB(*ReturnBB);
|
2020-12-15 07:25:35 +08:00
|
|
|
|
// Update successor info.
|
|
|
|
|
addSuccessorWithProb(InvokeMBB, &ReturnMBB);
|
|
|
|
|
for (auto &UnwindDest : UnwindDests) {
|
|
|
|
|
UnwindDest.first->setIsEHPad();
|
|
|
|
|
addSuccessorWithProb(InvokeMBB, UnwindDest.first, UnwindDest.second);
|
|
|
|
|
}
|
|
|
|
|
InvokeMBB->normalizeSuccProbs();
|
|
|
|
|
|
2016-12-08 05:17:47 +08:00
|
|
|
|
MF->addInvoke(&EHPadMBB, BeginSymbol, EndSymbol);
|
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
|
|
|
|
|
2020-09-02 17:12:27 +08:00
|
|
|
|
// If the unwinder does not preserve all registers, ensure that the
|
|
|
|
|
// function marks the clobbered registers as used.
|
|
|
|
|
const TargetRegisterInfo &TRI = *MF->getSubtarget().getRegisterInfo();
|
|
|
|
|
if (auto *RegMask = TRI.getCustomEHPadPreservedMask(*MF))
|
|
|
|
|
MF->getRegInfo().addPhysRegsUsedFromRegMask(RegMask);
|
|
|
|
|
|
2017-03-08 07:32:10 +08:00
|
|
|
|
LLT Ty = getLLTForType(*LP.getType(), *DL);
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Undef = MRI->createGenericVirtualRegister(Ty);
|
2017-03-08 07:04:06 +08:00
|
|
|
|
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.
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register ExceptionReg = TLI.getExceptionPointerRegister(PersonalityFn);
|
2017-03-08 07:04:06 +08:00
|
|
|
|
if (!ExceptionReg)
|
|
|
|
|
return false;
|
2016-11-10 06:39:54 +08:00
|
|
|
|
|
2017-03-08 07:04:06 +08:00
|
|
|
|
MBB.addLiveIn(ExceptionReg);
|
2019-06-24 23:50:29 +08:00
|
|
|
|
ArrayRef<Register> ResRegs = getOrCreateVRegs(LP);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
MIRBuilder.buildCopy(ResRegs[0], ExceptionReg);
|
2017-03-08 07:04:06 +08:00
|
|
|
|
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register SelectorReg = TLI.getExceptionSelectorRegister(PersonalityFn);
|
2017-03-08 07:04:06 +08:00
|
|
|
|
if (!SelectorReg)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
MBB.addLiveIn(SelectorReg);
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register PtrVReg = MRI->createGenericVirtualRegister(Tys[0]);
|
2017-03-08 07:04:06 +08:00
|
|
|
|
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())
|
2019-05-24 16:40:13 +08:00
|
|
|
|
return true;
|
2018-07-26 09:25:58 +08:00
|
|
|
|
|
2017-02-04 02:22:45 +08:00
|
|
|
|
if (AI.isStaticAlloca()) {
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Res = getOrCreateVReg(AI);
|
2017-02-04 02:22:45 +08:00
|
|
|
|
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.
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register 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) {
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register ExtElts = MRI->createGenericVirtualRegister(IntPtrTy);
|
2017-02-04 02:22:45 +08:00
|
|
|
|
MIRBuilder.buildZExtOrTrunc(ExtElts, NumElts);
|
|
|
|
|
NumElts = ExtElts;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-02 17:30:33 +08:00
|
|
|
|
Type *Ty = AI.getAllocatedType();
|
|
|
|
|
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register AllocSize = MRI->createGenericVirtualRegister(IntPtrTy);
|
|
|
|
|
Register TySize =
|
2019-08-28 03:54:27 +08:00
|
|
|
|
getOrCreateVReg(*ConstantInt::get(IntPtrIRTy, DL->getTypeAllocSize(Ty)));
|
2017-02-04 02:22:45 +08:00
|
|
|
|
MIRBuilder.buildMul(AllocSize, NumElts, TySize);
|
|
|
|
|
|
2019-08-28 03:54:27 +08:00
|
|
|
|
// 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.
|
2020-04-02 17:15:06 +08:00
|
|
|
|
Align StackAlign = MF->getSubtarget().getFrameLowering()->getStackAlign();
|
|
|
|
|
auto SAMinusOne = MIRBuilder.buildConstant(IntPtrTy, StackAlign.value() - 1);
|
2019-08-28 03:54:27 +08:00
|
|
|
|
auto AllocAdd = MIRBuilder.buildAdd(IntPtrTy, AllocSize, SAMinusOne,
|
|
|
|
|
MachineInstr::NoUWrap);
|
|
|
|
|
auto AlignCst =
|
2020-04-02 17:15:06 +08:00
|
|
|
|
MIRBuilder.buildConstant(IntPtrTy, ~(uint64_t)(StackAlign.value() - 1));
|
2019-08-28 03:54:27 +08:00
|
|
|
|
auto AlignedAlloc = MIRBuilder.buildAnd(IntPtrTy, AllocAdd, AlignCst);
|
|
|
|
|
|
2020-05-16 04:23:14 +08:00
|
|
|
|
Align Alignment = std::max(AI.getAlign(), DL->getPrefTypeAlign(Ty));
|
2020-04-02 17:15:06 +08:00
|
|
|
|
if (Alignment <= StackAlign)
|
|
|
|
|
Alignment = Align(1);
|
|
|
|
|
MIRBuilder.buildDynStackAlloc(getOrCreateVReg(AI), AlignedAlloc, Alignment);
|
2016-08-27 07:49:05 +08:00
|
|
|
|
|
2020-04-02 17:15:06 +08:00
|
|
|
|
MF->getFrameInfo().CreateVariableSizedObject(Alignment, &AI);
|
2017-02-04 02:22:45 +08:00
|
|
|
|
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.
|
2020-01-16 20:09:48 +08:00
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_VAARG, {getOrCreateVReg(U)},
|
|
|
|
|
{getOrCreateVReg(*U.getOperand(0)),
|
2020-07-01 22:31:56 +08:00
|
|
|
|
DL->getABITypeAlign(U.getType()).value()});
|
2017-02-16 07:22:33 +08:00
|
|
|
|
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.
|
2020-07-10 02:51:03 +08:00
|
|
|
|
if (cast<FixedVectorType>(U.getType())->getNumElements() == 1)
|
2020-04-17 21:36:01 +08:00
|
|
|
|
return translateCopy(U, *U.getOperand(1), MIRBuilder);
|
2018-05-16 18:32:02 +08:00
|
|
|
|
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Res = getOrCreateVReg(U);
|
|
|
|
|
Register Val = getOrCreateVReg(*U.getOperand(0));
|
|
|
|
|
Register Elt = getOrCreateVReg(*U.getOperand(1));
|
|
|
|
|
Register Idx = getOrCreateVReg(*U.getOperand(2));
|
2017-04-19 14:38:37 +08:00
|
|
|
|
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.
|
2020-07-10 02:51:03 +08:00
|
|
|
|
if (cast<FixedVectorType>(U.getOperand(0)->getType())->getNumElements() == 1)
|
2020-04-17 21:36:01 +08:00
|
|
|
|
return translateCopy(U, *U.getOperand(0), MIRBuilder);
|
|
|
|
|
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Res = getOrCreateVReg(U);
|
|
|
|
|
Register 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();
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Idx;
|
2018-10-25 22:04:54 +08:00
|
|
|
|
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) {
|
2020-02-14 03:30:50 +08:00
|
|
|
|
const LLT VecIdxTy = LLT::scalar(PreferredVecIdxWidth);
|
2020-01-23 19:51:35 +08:00
|
|
|
|
Idx = MIRBuilder.buildSExtOrTrunc(VecIdxTy, Idx).getReg(0);
|
2018-10-25 22:04:54 +08:00
|
|
|
|
}
|
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) {
|
2020-04-01 04:08:59 +08:00
|
|
|
|
ArrayRef<int> Mask;
|
|
|
|
|
if (auto *SVI = dyn_cast<ShuffleVectorInst>(&U))
|
|
|
|
|
Mask = SVI->getShuffleMask();
|
|
|
|
|
else
|
|
|
|
|
Mask = cast<ConstantExpr>(U).getShuffleMask();
|
2020-01-14 07:32:45 +08:00
|
|
|
|
ArrayRef<int> MaskAlloc = MF->allocateShuffleMask(Mask);
|
2020-01-16 20:09:48 +08:00
|
|
|
|
MIRBuilder
|
|
|
|
|
.buildInstr(TargetOpcode::G_SHUFFLE_VECTOR, {getOrCreateVReg(U)},
|
|
|
|
|
{getOrCreateVReg(*U.getOperand(0)),
|
|
|
|
|
getOrCreateVReg(*U.getOperand(1))})
|
2020-01-14 07:32:45 +08:00
|
|
|
|
.addShuffleMask(MaskAlloc);
|
2017-03-21 16:44:13 +08:00
|
|
|
|
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);
|
|
|
|
|
|
2020-01-13 04:54:09 +08:00
|
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
|
auto Flags = TLI.getAtomicMemOperandFlags(I, *DL);
|
[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
|
|
|
|
|
|
|
|
|
Type *ResType = I.getType();
|
|
|
|
|
Type *ValType = ResType->Type::getStructElementType(0);
|
|
|
|
|
|
|
|
|
|
auto Res = getOrCreateVRegs(I);
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register OldValRes = Res[0];
|
|
|
|
|
Register SuccessRes = Res[1];
|
|
|
|
|
Register Addr = getOrCreateVReg(*I.getPointerOperand());
|
|
|
|
|
Register Cmp = getOrCreateVReg(*I.getCompareOperand());
|
|
|
|
|
Register NewVal = getOrCreateVReg(*I.getNewValOperand());
|
[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
|
|
|
|
|
2019-11-15 04:11:00 +08:00
|
|
|
|
AAMDNodes AAMetadata;
|
|
|
|
|
I.getAAMetadata(AAMetadata);
|
|
|
|
|
|
[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
|
|
|
|
MIRBuilder.buildAtomicCmpXchgWithSuccess(
|
|
|
|
|
OldValRes, SuccessRes, Addr, Cmp, NewVal,
|
2020-03-31 17:43:50 +08:00
|
|
|
|
*MF->getMachineMemOperand(
|
|
|
|
|
MachinePointerInfo(I.getPointerOperand()), Flags,
|
|
|
|
|
DL->getTypeStoreSize(ValType), getMemOpAlign(I), AAMetadata, nullptr,
|
|
|
|
|
I.getSyncScopeID(), I.getSuccessOrdering(), I.getFailureOrdering()));
|
[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
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool IRTranslator::translateAtomicRMW(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
const AtomicRMWInst &I = cast<AtomicRMWInst>(U);
|
2020-01-13 04:54:09 +08:00
|
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
|
auto Flags = TLI.getAtomicMemOperandFlags(I, *DL);
|
[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
|
|
|
|
|
|
|
|
|
Type *ResType = I.getType();
|
|
|
|
|
|
2019-06-25 00:16:12 +08:00
|
|
|
|
Register Res = getOrCreateVReg(I);
|
|
|
|
|
Register Addr = getOrCreateVReg(*I.getPointerOperand());
|
|
|
|
|
Register Val = getOrCreateVReg(*I.getValOperand());
|
[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
|
|
|
|
|
|
|
|
|
unsigned Opcode = 0;
|
|
|
|
|
switch (I.getOperation()) {
|
|
|
|
|
default:
|
|
|
|
|
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;
|
2019-07-31 07:56:30 +08:00
|
|
|
|
case AtomicRMWInst::FAdd:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_FADD;
|
|
|
|
|
break;
|
|
|
|
|
case AtomicRMWInst::FSub:
|
|
|
|
|
Opcode = TargetOpcode::G_ATOMICRMW_FSUB;
|
|
|
|
|
break;
|
[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
|
|
|
|
}
|
|
|
|
|
|
2019-11-15 04:11:00 +08:00
|
|
|
|
AAMDNodes AAMetadata;
|
|
|
|
|
I.getAAMetadata(AAMetadata);
|
|
|
|
|
|
[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
|
|
|
|
MIRBuilder.buildAtomicRMW(
|
|
|
|
|
Opcode, Res, Addr, Val,
|
|
|
|
|
*MF->getMachineMemOperand(MachinePointerInfo(I.getPointerOperand()),
|
|
|
|
|
Flags, DL->getTypeStoreSize(ResType),
|
2020-03-31 17:43:50 +08:00
|
|
|
|
getMemOpAlign(I), AAMetadata, nullptr,
|
|
|
|
|
I.getSyncScopeID(), I.getOrdering()));
|
[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
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-02 22:16:39 +08:00
|
|
|
|
bool IRTranslator::translateFence(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
const FenceInst &Fence = cast<FenceInst>(U);
|
|
|
|
|
MIRBuilder.buildFence(static_cast<unsigned>(Fence.getOrdering()),
|
|
|
|
|
Fence.getSyncScopeID());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
[GlobalISel] translate freeze to new generic G_FREEZE
Summary:
As a follow up to https://reviews.llvm.org/D29014, add translation
support for freeze.
Introduce a new generic instruction G_FREEZE and translate freeze to it.
Reviewers: dsanders, aqjune, arsenm, aditya_nandakumar, t.p.northover, lebedev.ri, paquette, aemerson
Reviewed By: aqjune, arsenm
Subscribers: fhahn, lebedev.ri, wdng, rovka, hiraditya, jfb, volkan, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77795
2020-04-09 20:33:59 +08:00
|
|
|
|
bool IRTranslator::translateFreeze(const User &U,
|
|
|
|
|
MachineIRBuilder &MIRBuilder) {
|
|
|
|
|
const ArrayRef<Register> DstRegs = getOrCreateVRegs(U);
|
|
|
|
|
const ArrayRef<Register> SrcRegs = getOrCreateVRegs(*U.getOperand(0));
|
|
|
|
|
|
|
|
|
|
assert(DstRegs.size() == SrcRegs.size() &&
|
|
|
|
|
"Freeze with different source and destination type?");
|
|
|
|
|
|
|
|
|
|
for (unsigned I = 0; I < DstRegs.size(); ++I) {
|
|
|
|
|
MIRBuilder.buildFreeze(DstRegs[I], SrcRegs[I]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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-06-28 07:56:34 +08:00
|
|
|
|
MachineBasicBlock *PhiMBB = ComponentPHIs[0]->getParent();
|
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
|
|
|
|
|
2019-06-22 02:10:38 +08:00
|
|
|
|
SmallSet<const MachineBasicBlock *, 16> SeenPreds;
|
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);
|
2019-06-24 23:50:29 +08:00
|
|
|
|
ArrayRef<Register> ValRegs = getOrCreateVRegs(*PI->getIncomingValue(i));
|
2017-01-18 06:13:50 +08:00
|
|
|
|
for (auto Pred : getMachinePredBBs({IRPred, PI->getParent()})) {
|
2019-06-28 07:56:34 +08:00
|
|
|
|
if (SeenPreds.count(Pred) || !PhiMBB->isPredecessor(Pred))
|
2019-06-22 02:10:38 +08:00
|
|
|
|
continue;
|
|
|
|
|
SeenPreds.insert(Pred);
|
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());
|
2019-06-14 06:15:35 +08:00
|
|
|
|
|
2020-06-09 21:51:38 +08:00
|
|
|
|
auto &TLI = *MF->getSubtarget().getTargetLowering();
|
|
|
|
|
if (TLI.fallBackToDAGISel(Inst))
|
|
|
|
|
return false;
|
|
|
|
|
|
2019-06-14 06:15:35 +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
|
|
|
|
}
|
|
|
|
|
|
2019-06-25 00:16:12 +08:00
|
|
|
|
bool IRTranslator::translate(const Constant &C, Register Reg) {
|
2021-04-29 14:16:54 +08:00
|
|
|
|
// We only emit constants into the entry block from here. To prevent jumpy
|
|
|
|
|
// debug behaviour set the line to 0.
|
|
|
|
|
if (auto CurrInstDL = CurBuilder->getDL())
|
|
|
|
|
EntryBuilder->setDebugLoc(DILocation::get(C.getContext(), 0, 0,
|
|
|
|
|
CurrInstDL.getScope(),
|
|
|
|
|
CurrInstDL.getInlinedAt()));
|
|
|
|
|
|
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);
|
2020-02-18 03:40:44 +08:00
|
|
|
|
else if (isa<ConstantPointerNull>(C))
|
|
|
|
|
EntryBuilder->buildConstant(Reg, 0);
|
|
|
|
|
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)) {
|
2021-05-08 00:41:27 +08:00
|
|
|
|
if (!isa<FixedVectorType>(CAZ->getType()))
|
2017-03-11 05:23:13 +08:00
|
|
|
|
return false;
|
2017-03-15 07:45:06 +08:00
|
|
|
|
// Return the scalar if it is a <1 x Ty> vector.
|
2021-05-08 00:41:27 +08:00
|
|
|
|
unsigned NumElts = CAZ->getElementCount().getFixedValue();
|
|
|
|
|
if (NumElts == 1)
|
[GlobalISel][IRTranslator] Fix <1 x Ty> handling in ConstantExprs
Summary:
ConstantExprs involving operations on <1 x Ty> could translate into MIR
that failed to verify with:
*** Bad machine code: Reading virtual register without a def ***
The problem was that translate(const Constant &C, Register Reg) had
recursive calls that passed the same Reg in for the translation of a
subexpression, but without updating VMap for the subexpression first as
translate(const Constant &C, Register Reg) expects.
Fix this by using the same translateCopy helper function that we use for
translating Instructions. In some cases this causes extra G_COPY
MIR instructions to be generated.
Fixes https://bugs.llvm.org/show_bug.cgi?id=45576
Reviewers: arsenm, volkan, t.p.northover, aditya_nandakumar
Subscribers: jvesely, wdng, nhaehnle, rovka, hiraditya, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78378
2020-04-17 23:17:26 +08:00
|
|
|
|
return translateCopy(C, *CAZ->getElementValue(0u), *EntryBuilder.get());
|
2019-06-24 23:50:29 +08:00
|
|
|
|
SmallVector<Register, 4> Ops;
|
2021-05-08 00:41:27 +08:00
|
|
|
|
for (unsigned I = 0; I < NumElts; ++I) {
|
|
|
|
|
Constant &Elt = *CAZ->getElementValue(I);
|
2017-03-11 05:23:13 +08:00
|
|
|
|
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)
|
[GlobalISel][IRTranslator] Fix <1 x Ty> handling in ConstantExprs
Summary:
ConstantExprs involving operations on <1 x Ty> could translate into MIR
that failed to verify with:
*** Bad machine code: Reading virtual register without a def ***
The problem was that translate(const Constant &C, Register Reg) had
recursive calls that passed the same Reg in for the translation of a
subexpression, but without updating VMap for the subexpression first as
translate(const Constant &C, Register Reg) expects.
Fix this by using the same translateCopy helper function that we use for
translating Instructions. In some cases this causes extra G_COPY
MIR instructions to be generated.
Fixes https://bugs.llvm.org/show_bug.cgi?id=45576
Reviewers: arsenm, volkan, t.p.northover, aditya_nandakumar
Subscribers: jvesely, wdng, nhaehnle, rovka, hiraditya, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78378
2020-04-17 23:17:26 +08:00
|
|
|
|
return translateCopy(C, *CV->getElementAsConstant(0),
|
|
|
|
|
*EntryBuilder.get());
|
2019-06-24 23:50:29 +08:00
|
|
|
|
SmallVector<Register, 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)
|
[GlobalISel][IRTranslator] Fix <1 x Ty> handling in ConstantExprs
Summary:
ConstantExprs involving operations on <1 x Ty> could translate into MIR
that failed to verify with:
*** Bad machine code: Reading virtual register without a def ***
The problem was that translate(const Constant &C, Register Reg) had
recursive calls that passed the same Reg in for the translation of a
subexpression, but without updating VMap for the subexpression first as
translate(const Constant &C, Register Reg) expects.
Fix this by using the same translateCopy helper function that we use for
translating Instructions. In some cases this causes extra G_COPY
MIR instructions to be generated.
Fixes https://bugs.llvm.org/show_bug.cgi?id=45576
Reviewers: arsenm, volkan, t.p.northover, aditya_nandakumar
Subscribers: jvesely, wdng, nhaehnle, rovka, hiraditya, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D78378
2020-04-17 23:17:26 +08:00
|
|
|
|
return translateCopy(C, *CV->getOperand(0), *EntryBuilder.get());
|
2019-06-24 23:50:29 +08:00
|
|
|
|
SmallVector<Register, 4> Ops;
|
2017-05-05 05:43:12 +08:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2019-06-22 02:10:38 +08:00
|
|
|
|
void IRTranslator::finalizeBasicBlock() {
|
2020-08-05 01:55:27 +08:00
|
|
|
|
for (auto &BTB : SL->BitTestCases) {
|
|
|
|
|
// Emit header first, if it wasn't already emitted.
|
|
|
|
|
if (!BTB.Emitted)
|
|
|
|
|
emitBitTestHeader(BTB, BTB.Parent);
|
|
|
|
|
|
|
|
|
|
BranchProbability UnhandledProb = BTB.Prob;
|
|
|
|
|
for (unsigned j = 0, ej = BTB.Cases.size(); j != ej; ++j) {
|
|
|
|
|
UnhandledProb -= BTB.Cases[j].ExtraProb;
|
|
|
|
|
// Set the current basic block to the mbb we wish to insert the code into
|
|
|
|
|
MachineBasicBlock *MBB = BTB.Cases[j].ThisBB;
|
|
|
|
|
// If all cases cover a contiguous range, it is not necessary to jump to
|
|
|
|
|
// the default block after the last bit test fails. This is because the
|
|
|
|
|
// range check during bit test header creation has guaranteed that every
|
|
|
|
|
// case here doesn't go outside the range. In this case, there is no need
|
|
|
|
|
// to perform the last bit test, as it will always be true. Instead, make
|
|
|
|
|
// the second-to-last bit-test fall through to the target of the last bit
|
|
|
|
|
// test, and delete the last bit test.
|
|
|
|
|
|
|
|
|
|
MachineBasicBlock *NextMBB;
|
|
|
|
|
if (BTB.ContiguousRange && j + 2 == ej) {
|
|
|
|
|
// Second-to-last bit-test with contiguous range: fall through to the
|
|
|
|
|
// target of the final bit test.
|
|
|
|
|
NextMBB = BTB.Cases[j + 1].TargetBB;
|
|
|
|
|
} else if (j + 1 == ej) {
|
|
|
|
|
// For the last bit test, fall through to Default.
|
|
|
|
|
NextMBB = BTB.Default;
|
|
|
|
|
} else {
|
|
|
|
|
// Otherwise, fall through to the next bit test.
|
|
|
|
|
NextMBB = BTB.Cases[j + 1].ThisBB;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emitBitTestCase(BTB, NextMBB, UnhandledProb, BTB.Reg, BTB.Cases[j], MBB);
|
|
|
|
|
|
|
|
|
|
if (BTB.ContiguousRange && j + 2 == ej) {
|
2021-05-11 02:12:14 +08:00
|
|
|
|
// We need to record the replacement phi edge here that normally
|
|
|
|
|
// happens in emitBitTestCase before we delete the case, otherwise the
|
|
|
|
|
// phi edge will be lost.
|
|
|
|
|
addMachineCFGPred({BTB.Parent->getBasicBlock(),
|
|
|
|
|
BTB.Cases[ej - 1].TargetBB->getBasicBlock()},
|
|
|
|
|
MBB);
|
2020-08-05 01:55:27 +08:00
|
|
|
|
// Since we're not going to use the final bit test, remove it.
|
|
|
|
|
BTB.Cases.pop_back();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// This is "default" BB. We have two jumps to it. From "header" BB and from
|
|
|
|
|
// last "case" BB, unless the latter was skipped.
|
|
|
|
|
CFGEdge HeaderToDefaultEdge = {BTB.Parent->getBasicBlock(),
|
|
|
|
|
BTB.Default->getBasicBlock()};
|
|
|
|
|
addMachineCFGPred(HeaderToDefaultEdge, BTB.Parent);
|
|
|
|
|
if (!BTB.ContiguousRange) {
|
|
|
|
|
addMachineCFGPred(HeaderToDefaultEdge, BTB.Cases.back().ThisBB);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
SL->BitTestCases.clear();
|
|
|
|
|
|
2019-06-28 07:56:34 +08:00
|
|
|
|
for (auto &JTCase : SL->JTCases) {
|
|
|
|
|
// Emit header first, if it wasn't already emitted.
|
|
|
|
|
if (!JTCase.first.Emitted)
|
|
|
|
|
emitJumpTableHeader(JTCase.second, JTCase.first, JTCase.first.HeaderBB);
|
|
|
|
|
|
2019-06-22 02:10:38 +08:00
|
|
|
|
emitJumpTable(JTCase.second, JTCase.second.MBB);
|
2019-06-28 07:56:34 +08:00
|
|
|
|
}
|
2019-06-22 02:10:38 +08:00
|
|
|
|
SL->JTCases.clear();
|
2020-08-25 05:10:38 +08:00
|
|
|
|
|
|
|
|
|
for (auto &SwCase : SL->SwitchCases)
|
|
|
|
|
emitSwitchCase(SwCase, &CurBuilder->getMBB(), *CurBuilder);
|
|
|
|
|
SL->SwitchCases.clear();
|
2019-06-22 02:10:38 +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();
|
2019-06-22 02:10:38 +08:00
|
|
|
|
FuncInfo.clear();
|
2016-01-21 04:58:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-01 00:49:13 +08:00
|
|
|
|
/// Returns true if a BasicBlock \p BB within a variadic function contains a
|
|
|
|
|
/// variadic musttail call.
|
|
|
|
|
static bool checkForMustTailInVarArgFn(bool IsVarArg, const BasicBlock &BB) {
|
|
|
|
|
if (!IsVarArg)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Walk the block backwards, because tail calls usually only appear at the end
|
|
|
|
|
// of a block.
|
|
|
|
|
return std::any_of(BB.rbegin(), BB.rend(), [](const Instruction &I) {
|
|
|
|
|
const auto *CI = dyn_cast<CallInst>(&I);
|
|
|
|
|
return CI && CI->isMustTailCall();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
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) {
|
2019-08-15 23:54:37 +08:00
|
|
|
|
EntryBuilder = std::make_unique<CSEMIRBuilder>(CurMF);
|
2019-04-15 12:53:46 +08:00
|
|
|
|
CSEInfo = &Wrapper.get(TPC->getCSEConfig());
|
2019-01-16 08:40:37 +08:00
|
|
|
|
EntryBuilder->setCSEInfo(CSEInfo);
|
2019-08-15 23:54:37 +08:00
|
|
|
|
CurBuilder = std::make_unique<CSEMIRBuilder>(CurMF);
|
2019-01-16 08:40:37 +08:00
|
|
|
|
CurBuilder->setCSEInfo(CSEInfo);
|
|
|
|
|
} else {
|
2019-08-15 23:54:37 +08:00
|
|
|
|
EntryBuilder = std::make_unique<MachineIRBuilder>();
|
|
|
|
|
CurBuilder = std::make_unique<MachineIRBuilder>();
|
2019-01-16 08:40:37 +08:00
|
|
|
|
}
|
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();
|
2019-08-15 23:54:37 +08:00
|
|
|
|
ORE = std::make_unique<OptimizationRemarkEmitter>(&F);
|
2020-08-29 07:21:34 +08:00
|
|
|
|
const TargetMachine &TM = MF->getTarget();
|
2020-09-15 16:25:38 +08:00
|
|
|
|
TM.resetTargetOptions(F);
|
2020-08-29 07:21:34 +08:00
|
|
|
|
EnableOpts = OptLevel != CodeGenOpt::None && !skipFunction(F);
|
2019-06-22 02:10:38 +08:00
|
|
|
|
FuncInfo.MF = MF;
|
2020-08-29 07:21:34 +08:00
|
|
|
|
if (EnableOpts)
|
|
|
|
|
FuncInfo.BPI = &getAnalysis<BranchProbabilityInfoWrapperPass>().getBPI();
|
|
|
|
|
else
|
|
|
|
|
FuncInfo.BPI = nullptr;
|
|
|
|
|
|
2020-12-23 14:52:36 +08:00
|
|
|
|
FuncInfo.CanLowerReturn = CLI->checkReturnTypeForCallConv(*MF);
|
|
|
|
|
|
2019-06-22 02:10:38 +08:00
|
|
|
|
const auto &TLI = *MF->getSubtarget().getTargetLowering();
|
2020-08-29 07:21:34 +08:00
|
|
|
|
|
2019-08-15 23:54:37 +08:00
|
|
|
|
SL = std::make_unique<GISelSwitchLowering>(this, FuncInfo);
|
2019-06-22 02:10:38 +08:00
|
|
|
|
SL->init(TLI, TM, *DL);
|
|
|
|
|
|
2020-08-29 07:21:34 +08:00
|
|
|
|
|
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
|
|
|
|
|
2019-05-24 16:40:13 +08:00
|
|
|
|
DebugLoc DbgLoc = F.getEntryBlock().getFirstNonPHI()->getDebugLoc();
|
|
|
|
|
SwiftError.setFunction(CurMF);
|
|
|
|
|
SwiftError.createEntriesInEntryBlock(DbgLoc);
|
|
|
|
|
|
2019-10-01 00:49:13 +08:00
|
|
|
|
bool IsVarArg = F.isVarArg();
|
|
|
|
|
bool HasMustTailInVarArgFn = false;
|
|
|
|
|
|
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();
|
2019-10-01 00:49:13 +08:00
|
|
|
|
|
|
|
|
|
if (!HasMustTailInVarArgFn)
|
|
|
|
|
HasMustTailInVarArgFn = checkForMustTailInVarArgFn(IsVarArg, BB);
|
2017-03-16 02:22:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-10-01 00:49:13 +08:00
|
|
|
|
MF->getFrameInfo().setHasMustTailInVarArgFunc(HasMustTailInVarArgFn);
|
|
|
|
|
|
2017-03-16 02:22:33 +08:00
|
|
|
|
// Make our arguments/constants entry block fallthrough to the IR entry block.
|
|
|
|
|
EntryBB->addSuccessor(&getMBB(F.front()));
|
|
|
|
|
|
2021-03-17 02:56:32 +08:00
|
|
|
|
if (CLI->fallBackToDAGISel(*MF)) {
|
2020-06-25 15:19:49 +08:00
|
|
|
|
OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",
|
|
|
|
|
F.getSubprogram(), &F.getEntryBlock());
|
|
|
|
|
R << "unable to lower function: " << ore::NV("Prototype", F.getType());
|
|
|
|
|
reportTranslationError(*MF, *TPC, *ORE, R);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 05:05:38 +08:00
|
|
|
|
// Lower the actual args into this basic block.
|
2019-06-27 16:54:17 +08:00
|
|
|
|
SmallVector<ArrayRef<Register>, 8> VRegArgs;
|
2017-12-01 04:06:02 +08:00
|
|
|
|
for (const Argument &Arg: F.args()) {
|
2020-07-02 17:06:41 +08:00
|
|
|
|
if (DL->getTypeStoreSize(Arg.getType()).isZero())
|
2017-12-01 04:06:02 +08:00
|
|
|
|
continue; // Don't handle zero sized types.
|
2019-06-27 16:54:17 +08:00
|
|
|
|
ArrayRef<Register> VRegs = getOrCreateVRegs(Arg);
|
|
|
|
|
VRegArgs.push_back(VRegs);
|
2019-05-24 16:40:13 +08:00
|
|
|
|
|
2019-06-27 16:54:17 +08:00
|
|
|
|
if (Arg.hasSwiftErrorAttr()) {
|
|
|
|
|
assert(VRegs.size() == 1 && "Too many vregs for Swift error");
|
|
|
|
|
SwiftError.setCurrentVReg(EntryBB, SwiftError.getFunctionArg(), VRegs[0]);
|
|
|
|
|
}
|
2017-12-01 04:06:02 +08:00
|
|
|
|
}
|
2018-05-16 18:32:02 +08:00
|
|
|
|
|
2020-12-23 14:52:36 +08:00
|
|
|
|
if (!CLI->lowerFormalArguments(*EntryBuilder.get(), F, VRegArgs, FuncInfo)) {
|
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-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);
|
2020-02-19 06:42:49 +08:00
|
|
|
|
RAIIMFObserverInstaller ObsInstall(*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);
|
2019-09-11 07:34:45 +08:00
|
|
|
|
HasTailCall = false;
|
[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) {
|
2019-09-11 07:34:45 +08:00
|
|
|
|
// If we translated a tail call in the last step, then we know
|
|
|
|
|
// everything after the call is either a return, or something that is
|
|
|
|
|
// handled by the call itself. (E.g. a lifetime marker or assume
|
|
|
|
|
// intrinsic.) In this case, we should stop translating the block and
|
|
|
|
|
// move on.
|
|
|
|
|
if (HasTailCall)
|
|
|
|
|
break;
|
[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(&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
|
|
|
|
}
|
2019-06-22 02:10:38 +08:00
|
|
|
|
|
|
|
|
|
finalizeBasicBlock();
|
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();
|
|
|
|
|
|
2019-05-24 16:40:13 +08:00
|
|
|
|
SwiftError.propagateVRegs();
|
|
|
|
|
|
2017-02-24 07:57:36 +08:00
|
|
|
|
// 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;
|
|
|
|
|
}
|