Index: llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp +++ llvm/trunk/lib/Target/AArch64/AArch64InstructionSelector.cpp @@ -1163,9 +1163,19 @@ 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 Index: llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-bitcast.mir =================================================================== --- llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-bitcast.mir +++ llvm/trunk/test/CodeGen/AArch64/GlobalISel/select-bitcast.mir @@ -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 } ... --- @@ -210,3 +212,53 @@ %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>) +... Index: llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp +++ llvm/trunk/utils/TableGen/GlobalISelEmitter.cpp @@ -182,14 +182,6 @@ static Error isTrivialOperatorNode(const TreePatternNode *N) { std::string Explanation = ""; std::string Separator = ""; - if (N->isLeaf()) { - if (isa(N->getLeafValue())) - return Error::success(); - - Explanation = "Is a leaf"; - Separator = ", "; - } - if (N->hasAnyPredicate()) { Explanation = Separator + "Has a predicate (" + explainPredicates(N) + ")"; Separator = ", "; @@ -200,7 +192,7 @@ Separator = ", "; } - if (!N->isLeaf() && !N->hasAnyPredicate() && !N->getTransformFn()) + if (!N->hasAnyPredicate() && !N->getTransformFn()) return Error::success(); return failedImport(Explanation); @@ -1767,23 +1759,29 @@ // LiteralInt because it can cover more nodes but theres an exception to // this. G_CONSTANT's are less important than either of those two because they // are more permissive. - if (const InstructionOperandMatcher *AOM = - dyn_cast(this)) { - if (AOM->getInsnMatcher().isConstantInstruction()) { - if (B.Kind == OPM_Int) { - return false; - } - } - } - if (const InstructionOperandMatcher *BOM = - dyn_cast(&B)) { - if (BOM->getInsnMatcher().isConstantInstruction()) { - if (Kind == OPM_Int) { - return true; - } - } + + const InstructionOperandMatcher *AOM = + dyn_cast(this); + const InstructionOperandMatcher *BOM = + dyn_cast(&B); + bool AIsConstantInsn = AOM && AOM->getInsnMatcher().isConstantInstruction(); + bool BIsConstantInsn = BOM && BOM->getInsnMatcher().isConstantInstruction(); + + if (AOM && BOM) { + // The relative priorities between a G_CONSTANT and any other instruction + // don't actually matter but this code is needed to ensure a strict weak + // ordering. This is particularly important on Windows where the rules will + // be incorrectly sorted without it. + if (AIsConstantInsn != BIsConstantInsn) + return AIsConstantInsn < BIsConstantInsn; + return false; } + if (AOM && AIsConstantInsn && (B.Kind == OPM_Int || B.Kind == OPM_LiteralInt)) + return false; + if (BOM && BIsConstantInsn && (Kind == OPM_Int || Kind == OPM_LiteralInt)) + return true; + return Kind < B.Kind; } @@ -2287,8 +2285,42 @@ 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(RC); + + auto &DstMIBuilder = M.addAction(0, &DstI, InsnMatcher); + DstMIBuilder.addRenderer(0, InsnMatcher, DstIOperand.Name); + DstMIBuilder.addRenderer(0, InsnMatcher, Dst->getName()); + M.addAction(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(); @@ -2301,14 +2333,6 @@ 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; @@ -2537,13 +2561,14 @@ // for the matcher to reference them with. std::vector 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";