Skip to content

Commit

Permalink
[globalisel][tablegen] Support zero-instruction emission.
Browse files Browse the repository at this point in the history
Summary:
Support the case where an operand of a pattern is also the whole of the
result pattern. In this case the original result and all its uses must be
replaced by the operand. However, register class restrictions can require
a COPY. This patch handles both cases by always emitting the copy and
leaving it for the register allocator to optimize.

Depends on D35833

Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar

Subscribers: javed.absar, kristof.beyls, igorb, llvm-commits

Differential Revision: https://reviews.llvm.org/D36084

llvm-svn: 310716
  • Loading branch information
dsandersllvm committed Aug 11, 2017
1 parent 16bddf2 commit 1fb1ce0
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 26 deletions.
12 changes: 11 additions & 1 deletion llvm/lib/Target/AArch64/AArch64InstructionSelector.cpp
Expand Up @@ -1163,9 +1163,19 @@ bool AArch64InstructionSelector::select(MachineInstr &I) const {


case TargetOpcode::G_INTTOPTR:
case TargetOpcode::G_BITCAST:
// The importer is currently unable to import pointer types since they
// didn't exist in SelectionDAG.
return selectCopy(I, TII, MRI, TRI, RBI);

case TargetOpcode::G_BITCAST:
// Imported SelectionDAG rules can handle every bitcast except those that
// bitcast from a type to the same type. Ideally, these shouldn't occur
// but we might not run an optimizer that deletes them.
if (MRI.getType(I.getOperand(0).getReg()) ==
MRI.getType(I.getOperand(1).getReg()))
return selectCopy(I, TII, MRI, TRI, RBI);
return false;

case TargetOpcode::G_FPEXT: {
if (MRI.getType(I.getOperand(0).getReg()) != LLT::scalar(64)) {
DEBUG(dbgs() << "G_FPEXT to type " << Ty
Expand Down
52 changes: 52 additions & 0 deletions llvm/test/CodeGen/AArch64/GlobalISel/select-bitcast.mir
Expand Up @@ -11,6 +11,8 @@
define void @bitcast_s64_fpr() { ret void }
define void @bitcast_s64_gpr_fpr() { ret void }
define void @bitcast_s64_fpr_gpr() { ret void }
define void @bitcast_s64_v2f32_fpr() { ret void }
define void @bitcast_s64_v8i8_fpr() { ret void }
...

---
Expand Down Expand Up @@ -210,3 +212,53 @@ body: |
%1(s64) = G_BITCAST %0
%x0 = COPY %1(s64)
...

---
# CHECK-LABEL: name: bitcast_s64_v2f32_fpr
name: bitcast_s64_v2f32_fpr
legalized: true
regBankSelected: true

# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: fpr64, preferred-register: '' }
# CHECK-NEXT: - { id: 1, class: fpr64, preferred-register: '' }
registers:
- { id: 0, class: fpr }
- { id: 1, class: fpr }

# CHECK: body:
# CHECK: %0 = COPY %d0
# CHECK: %1 = COPY %0
body: |
bb.0:
liveins: %d0
%0(s64) = COPY %d0
%1(<2 x s32>) = G_BITCAST %0
%x0 = COPY %1(<2 x s32>)
...

---
# CHECK-LABEL: name: bitcast_s64_v8i8_fpr
name: bitcast_s64_v8i8_fpr
legalized: true
regBankSelected: true

# CHECK: registers:
# CHECK-NEXT: - { id: 0, class: fpr64, preferred-register: '' }
# CHECK-NEXT: - { id: 1, class: fpr64, preferred-register: '' }
registers:
- { id: 0, class: fpr }
- { id: 1, class: fpr }

# CHECK: body:
# CHECK: %0 = COPY %d0
# CHECK: %1 = COPY %0
body: |
bb.0:
liveins: %d0
%0(s64) = COPY %d0
%1(<8 x s8>) = G_BITCAST %0
%x0 = COPY %1(<8 x s8>)
...
69 changes: 44 additions & 25 deletions llvm/utils/TableGen/GlobalISelEmitter.cpp
Expand Up @@ -182,14 +182,6 @@ static Error failedImport(const Twine &Reason) {
static Error isTrivialOperatorNode(const TreePatternNode *N) {
std::string Explanation = "";
std::string Separator = "";
if (N->isLeaf()) {
if (isa<IntInit>(N->getLeafValue()))
return Error::success();

Explanation = "Is a leaf";
Separator = ", ";
}

if (N->hasAnyPredicate()) {
Explanation = Separator + "Has a predicate (" + explainPredicates(N) + ")";
Separator = ", ";
Expand All @@ -200,7 +192,7 @@ static Error isTrivialOperatorNode(const TreePatternNode *N) {
Separator = ", ";
}

if (!N->isLeaf() && !N->hasAnyPredicate() && !N->getTransformFn())
if (!N->hasAnyPredicate() && !N->getTransformFn())
return Error::success();

return failedImport(Explanation);
Expand Down Expand Up @@ -2287,8 +2279,42 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
return failedImport("Src pattern root isn't a trivial operator (" +
toString(std::move(Err)) + ")");

if (Dst->isLeaf())
InstructionMatcher &InsnMatcherTemp = M.addInstructionMatcher(Src->getName());
unsigned TempOpIdx = 0;
auto InsnMatcherOrError =
createAndImportSelDAGMatcher(InsnMatcherTemp, Src, TempOpIdx);
if (auto Error = InsnMatcherOrError.takeError())
return std::move(Error);
InstructionMatcher &InsnMatcher = InsnMatcherOrError.get();

if (Dst->isLeaf()) {
Record *RCDef = getInitValueAsRegClass(Dst->getLeafValue());

const CodeGenRegisterClass &RC = Target.getRegisterClass(RCDef);
if (RCDef) {
// We need to replace the def and all its uses with the specified
// operand. However, we must also insert COPY's wherever needed.
// For now, emit a copy and let the register allocator clean up.
auto &DstI = Target.getInstruction(RK.getDef("COPY"));
const auto &DstIOperand = DstI.Operands[0];

OperandMatcher &OM0 = InsnMatcher.getOperand(0);
OM0.setSymbolicName(DstIOperand.Name);
OM0.addPredicate<RegisterBankOperandMatcher>(RC);

auto &DstMIBuilder = M.addAction<BuildMIAction>(0, &DstI, InsnMatcher);
DstMIBuilder.addRenderer<CopyRenderer>(0, InsnMatcher, DstIOperand.Name);
DstMIBuilder.addRenderer<CopyRenderer>(0, InsnMatcher, Dst->getName());
M.addAction<ConstrainOperandToRegClassAction>(0, 0, RC);

// We're done with this pattern! It's eligible for GISel emission; return
// it.
++NumPatternImported;
return std::move(M);
}

return failedImport("Dst pattern root isn't a known leaf");
}

// Start with the defined operands (i.e., the results of the root operator).
Record *DstOp = Dst->getOperator();
Expand All @@ -2301,14 +2327,6 @@ Expected<RuleMatcher> GlobalISelEmitter::runOnPattern(const PatternToMatch &P) {
to_string(Src->getExtTypes().size()) + " def(s) vs " +
to_string(DstI.Operands.NumDefs) + " def(s))");

InstructionMatcher &InsnMatcherTemp = M.addInstructionMatcher(Src->getName());
unsigned TempOpIdx = 0;
auto InsnMatcherOrError =
createAndImportSelDAGMatcher(InsnMatcherTemp, Src, TempOpIdx);
if (auto Error = InsnMatcherOrError.takeError())
return std::move(Error);
InstructionMatcher &InsnMatcher = InsnMatcherOrError.get();

// The root of the match also has constraints on the register bank so that it
// matches the result instruction.
unsigned OpIdx = 0;
Expand Down Expand Up @@ -2537,13 +2555,14 @@ void GlobalISelEmitter::run(raw_ostream &OS) {
// for the matcher to reference them with.
std::vector<LLTCodeGen> TypeObjects = {
LLT::scalar(8), LLT::scalar(16), LLT::scalar(32),
LLT::scalar(64), LLT::scalar(80), LLT::vector(8, 1),
LLT::vector(16, 1), LLT::vector(32, 1), LLT::vector(64, 1),
LLT::vector(8, 8), LLT::vector(16, 8), LLT::vector(32, 8),
LLT::vector(64, 8), LLT::vector(4, 16), LLT::vector(8, 16),
LLT::vector(16, 16), LLT::vector(32, 16), LLT::vector(2, 32),
LLT::vector(4, 32), LLT::vector(8, 32), LLT::vector(16, 32),
LLT::vector(2, 64), LLT::vector(4, 64), LLT::vector(8, 64),
LLT::scalar(64), LLT::scalar(80), LLT::scalar(128),
LLT::vector(8, 1), LLT::vector(16, 1), LLT::vector(32, 1),
LLT::vector(64, 1), LLT::vector(8, 8), LLT::vector(16, 8),
LLT::vector(32, 8), LLT::vector(64, 8), LLT::vector(4, 16),
LLT::vector(8, 16), LLT::vector(16, 16), LLT::vector(32, 16),
LLT::vector(2, 32), LLT::vector(4, 32), LLT::vector(8, 32),
LLT::vector(16, 32), LLT::vector(2, 64), LLT::vector(4, 64),
LLT::vector(8, 64),
};
std::sort(TypeObjects.begin(), TypeObjects.end());
OS << "enum {\n";
Expand Down

0 comments on commit 1fb1ce0

Please sign in to comment.