// LastCrossRegCpyIdx.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
+ // 41: FPExt: 16 to 32. <-- This must match FPExt16To32Idx.
+ {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
+ {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR16 - PMI_Min], 1},
+ // 43: FPExt: 16 to 32. <-- This must match FPExt16To64Idx.
+ {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
+ {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR16 - PMI_Min], 1},
+ // 45: FPExt: 32 to 64. <-- This must match FPExt32To64Idx.
+ {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
+ {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
+ // 47: FPExt vector: 64 to 128. <-- This must match FPExt64To128Idx.
+ {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR128 - PMI_Min], 1},
+ {&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
};
bool AArch64GenRegisterBankInfo::checkPartialMap(unsigned Idx,
ValMappingIdx <= LastCrossRegCpyIdx && "Mapping out of bound");
return &ValMappings[ValMappingIdx];
}
+
+const RegisterBankInfo::ValueMapping *
+AArch64GenRegisterBankInfo::getFPExtMapping(unsigned DstSize,
+ unsigned SrcSize) {
+ // We support:
+ // - For Scalar:
+ // - 16 to 32.
+ // - 16 to 64.
+ // - 32 to 64.
+ // => FPR 16 to FPR 32|64
+ // => FPR 32 to FPR 64
+ // - For vectors:
+ // - v4f16 to v4f32
+ // - v2f32 to v2f64
+ // => FPR 64 to FPR 128
+
+ // Check that we have been asked sensible sizes.
+ if (SrcSize == 16) {
+ assert((DstSize == 32 || DstSize == 64) && "Unexpected half extension");
+ if (DstSize == 32)
+ return &ValMappings[FPExt16To32Idx];
+ return &ValMappings[FPExt16To64Idx];
+ }
+
+ if (SrcSize == 32) {
+ assert(DstSize == 64 && "Unexpected float extension");
+ return &ValMappings[FPExt32To64Idx];
+ }
+ assert((SrcSize == 64 || DstSize == 128) && "Unexpected vector extension");
+ return &ValMappings[FPExt64To128Idx];
+}
} // End llvm namespace.
CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 64);
CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 64);
+#define CHECK_VALUEMAP_FPEXT(DstSize, SrcSize) \
+ do { \
+ unsigned PartialMapDstIdx = PMI_FPR##DstSize - PMI_Min; \
+ unsigned PartialMapSrcIdx = PMI_FPR##SrcSize - PMI_Min; \
+ (void)PartialMapDstIdx; \
+ (void)PartialMapSrcIdx; \
+ const ValueMapping *Map = getFPExtMapping(DstSize, SrcSize); \
+ (void)Map; \
+ assert(Map[0].BreakDown == \
+ &AArch64GenRegisterBankInfo::PartMappings[PartialMapDstIdx] && \
+ Map[0].NumBreakDowns == 1 && "FPR" #DstSize \
+ " Dst is incorrectly initialized"); \
+ assert(Map[1].BreakDown == \
+ &AArch64GenRegisterBankInfo::PartMappings[PartialMapSrcIdx] && \
+ Map[1].NumBreakDowns == 1 && "FPR" #SrcSize \
+ " Src is incorrectly initialized"); \
+ \
+ } while (false)
+
+ CHECK_VALUEMAP_FPEXT(32, 16);
+ CHECK_VALUEMAP_FPEXT(64, 16);
+ CHECK_VALUEMAP_FPEXT(64, 32);
+ CHECK_VALUEMAP_FPEXT(128, 64);
+
assert(verify(TRI) && "Invalid register bank information");
}
case TargetOpcode::G_FMUL:
case TargetOpcode::G_FDIV:
return getSameKindOfOperandsMapping(MI);
+ case TargetOpcode::G_FPEXT: {
+ LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
+ LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());
+ return getInstructionMapping(
+ DefaultMappingID, /*Cost*/ 1,
+ getFPExtMapping(DstTy.getSizeInBits(), SrcTy.getSizeInBits()),
+ /*NumOperands*/ 2);
+ }
case TargetOpcode::COPY: {
unsigned DstReg = MI.getOperand(0).getReg();
unsigned SrcReg = MI.getOperand(1).getReg();
DistanceBetweenRegBanks = 3,
FirstCrossRegCpyIdx = 25,
LastCrossRegCpyIdx = 39,
- DistanceBetweenCrossRegCpy = 2
+ DistanceBetweenCrossRegCpy = 2,
+ FPExt16To32Idx = 41,
+ FPExt16To64Idx = 43,
+ FPExt32To64Idx = 45,
+ FPExt64To128Idx = 47,
};
static bool checkPartialMap(unsigned Idx, unsigned ValStartIdx,
static const RegisterBankInfo::ValueMapping *
getCopyMapping(unsigned DstBankID, unsigned SrcBankID, unsigned Size);
+ /// Get the instruction mapping for G_FPEXT.
+ ///
+ /// \pre (DstSize, SrcSize) pair is one of the following:
+ /// (32, 16), (64, 16), (64, 32), (128, 64)
+ ///
+ /// \return An InstructionMapping with statically allocated OperandsMapping.
+ static const RegisterBankInfo::ValueMapping *
+ getFPExtMapping(unsigned DstSize, unsigned SrcSize);
+
#define GET_TARGET_REGBANK_CLASS
#include "AArch64GenRegisterBank.inc"
};
store double %vres, double* %addr
ret void
}
+
+ define void @fp16Ext32() { ret void }
+ define void @fp16Ext64() { ret void }
+ define void @fp32Ext64() { ret void }
...
---
RET_ReallyLR
...
+
+---
+# Make sure we map FPEXT on FPR register bank.
+# CHECK-LABEL: name: fp16Ext32
+name: fp16Ext32
+alignment: 2
+legalized: true
+# CHECK: registers:
+# CHECK-NEXT: - { id: 0, class: gpr, preferred-register: '' }
+# CHECK-NEXT: - { id: 1, class: gpr, preferred-register: '' }
+# CHECK-NEXT: - { id: 2, class: fpr, preferred-register: '' }
+# CHECK-NEXT: - { id: 3, class: fpr, preferred-register: '' }
+registers:
+ - { id: 0, class: _ }
+ - { id: 1, class: _ }
+ - { id: 2, class: _ }
+# CHECK: %1:gpr(s32) = COPY %w0
+# CHECK-NEXT: %0:gpr(s16) = G_TRUNC %1
+# %0 has been mapped to GPR, we need to repair to match FPR.
+# CHECK-NEXT: %3:fpr(s16) = COPY %0
+# CHECK-NEXT: %2:fpr(s32) = G_FPEXT %3
+# CHECK-NEXT: %s0 = COPY %2
+# CHECK-NEXT: RET_ReallyLR
+
+body: |
+ bb.1:
+ liveins: %w0
+
+ %1(s32) = COPY %w0
+ %0(s16) = G_TRUNC %1(s32)
+ %2(s32) = G_FPEXT %0(s16)
+ %s0 = COPY %2(s32)
+ RET_ReallyLR implicit %s0
+
+...
+
+---
+# Make sure we map FPEXT on FPR register bank.
+# CHECK-LABEL: name: fp16Ext64
+name: fp16Ext64
+alignment: 2
+legalized: true
+# CHECK: registers:
+# CHECK-NEXT: - { id: 0, class: gpr, preferred-register: '' }
+# CHECK-NEXT: - { id: 1, class: gpr, preferred-register: '' }
+# CHECK-NEXT: - { id: 2, class: fpr, preferred-register: '' }
+# CHECK-NEXT: - { id: 3, class: fpr, preferred-register: '' }
+registers:
+ - { id: 0, class: _ }
+ - { id: 1, class: _ }
+ - { id: 2, class: _ }
+# CHECK: %1:gpr(s32) = COPY %w0
+# CHECK-NEXT: %0:gpr(s16) = G_TRUNC %1
+# %0 has been mapped to GPR, we need to repair to match FPR.
+# CHECK-NEXT: %3:fpr(s16) = COPY %0
+# CHECK-NEXT: %2:fpr(s64) = G_FPEXT %3
+# CHECK-NEXT: %d0 = COPY %2
+# CHECK-NEXT: RET_ReallyLR
+
+body: |
+ bb.1:
+ liveins: %w0
+
+ %1(s32) = COPY %w0
+ %0(s16) = G_TRUNC %1(s32)
+ %2(s64) = G_FPEXT %0(s16)
+ %d0 = COPY %2(s64)
+ RET_ReallyLR implicit %d0
+
+...
+
+---
+# Make sure we map FPEXT on FPR register bank.
+# CHECK-LABEL: name: fp32Ext64
+name: fp32Ext64
+alignment: 2
+legalized: true
+# CHECK: registers:
+# CHECK-NEXT: - { id: 0, class: gpr, preferred-register: '' }
+# CHECK-NEXT: - { id: 1, class: fpr, preferred-register: '' }
+# CHECK-NEXT: - { id: 2, class: fpr, preferred-register: '' }
+registers:
+ - { id: 0, class: _ }
+ - { id: 1, class: _ }
+# CHECK: %0:gpr(s32) = COPY %w0
+# %0 has been mapped to GPR, we need to repair to match FPR.
+# CHECK-NEXT: %2:fpr(s32) = COPY %0
+# CHECK-NEXT: %1:fpr(s64) = G_FPEXT %2
+# CHECK-NEXT: %d0 = COPY %1
+# CHECK-NEXT: RET_ReallyLR
+body: |
+ bb.1:
+ liveins: %w0
+
+ %0(s32) = COPY %w0
+ %1(s64) = G_FPEXT %0(s32)
+ %d0 = COPY %1(s64)
+ RET_ReallyLR implicit %d0
+
+...