| // This is to test the scenario where different HwMode attributes coexist. | |
| // RUN: llvm-tblgen -gen-register-info -register-info-debug -I %p/../../include %s -o - 2>&1 >/dev/null | FileCheck %s --check-prefix=CHECK-REG | |
| // RUN: llvm-tblgen -gen-subtarget -I %p/../../include %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-SUBTARGET | |
| include "llvm/Target/Target.td" | |
| def TestTargetInstrInfo : InstrInfo; | |
| def TestTarget : Target { | |
| let InstructionSet = TestTargetInstrInfo; | |
| } | |
| def Feat1 : SubtargetFeature<"feat1", "HasFeat1", "true", "enable feature 1">; | |
| def Feat2 : SubtargetFeature<"feat2", "HasFeat2", "true", "enable feature 2">; | |
| def HasFeat1 : Predicate<"Subtarget->hasFeat1()">, | |
| AssemblerPredicate<(all_of Feat1)>; | |
| def HasFeat2 : Predicate<"Subtarget->hasFeat2()">, | |
| AssemblerPredicate<(all_of Feat2)>; | |
| def TestMode : HwMode<[HasFeat1]>; | |
| def TestMode1 : HwMode<[HasFeat2]>; | |
| def TestMode2 : HwMode<[HasFeat1, HasFeat2]>; | |
| class MyReg<string n> | |
| : Register<n> { | |
| let Namespace = "Test"; | |
| } | |
| class MyClass<int size, list<ValueType> types, dag registers> | |
| : RegisterClass<"Test", types, size, registers> { | |
| let Size = size; | |
| } | |
| def X0 : MyReg<"x0">; | |
| def X1 : MyReg<"x1">; | |
| def X2 : MyReg<"x2">; | |
| def X3 : MyReg<"x3">; | |
| def X4 : MyReg<"x4">; | |
| def X5 : MyReg<"x5">; | |
| def X6 : MyReg<"x6">; | |
| def X7 : MyReg<"x7">; | |
| def X8 : MyReg<"x8">; | |
| def X9 : MyReg<"x9">; | |
| def X10 : MyReg<"x10">; | |
| def X11 : MyReg<"x11">; | |
| def X12 : MyReg<"x12">; | |
| def X13 : MyReg<"x13">; | |
| def X14 : MyReg<"x14">; | |
| def X15 : MyReg<"x15">; | |
| def ValueModeVT : ValueTypeByHwMode<[DefaultMode, TestMode, TestMode1], | |
| [i32, i64, f32]>; | |
| let RegInfos = RegInfoByHwMode<[DefaultMode, TestMode], | |
| [RegInfo<32,32,32>, RegInfo<64,64,64>]> in | |
| def XRegs : MyClass<32, [ValueModeVT], (sequence "X%u", 0, 15)>; | |
| def sub_even : SubRegIndex<32> { | |
| let SubRegRanges = SubRegRangeByHwMode<[DefaultMode, TestMode], | |
| [SubRegRange<32>, SubRegRange<64>]>; | |
| } | |
| def sub_odd : SubRegIndex<32, 32> { | |
| let SubRegRanges = SubRegRangeByHwMode<[DefaultMode, TestMode], | |
| [SubRegRange<32, 32>, SubRegRange<64, 64>]>; | |
| } | |
| def XPairs : RegisterTuples<[sub_even, sub_odd], | |
| [(decimate (rotl XRegs, 0), 2), | |
| (decimate (rotl XRegs, 1), 2)]>; | |
| let RegInfos = RegInfoByHwMode<[DefaultMode, TestMode], | |
| [RegInfo<64,64,32>, RegInfo<128,128,64>]> in | |
| def XPairsClass : MyClass<64, [untyped], (add XPairs)>; | |
| // Modes who are not controlling Register related features will be manipulated | |
| // the same as DefaultMode. | |
| // CHECK-REG-LABEL: RegisterClass XRegs: | |
| // CHECK-REG: SpillSize: { DefaultMode:32 TestMode:64 TestMode1:32 TestMode2:32 } | |
| // CHECK-REG: SpillAlignment: { DefaultMode:32 TestMode:64 TestMode1:32 TestMode2:32 } | |
| // CHECK-REG: Regs: X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 | |
| // CHECK-REG-LABEL: RegisterClass XPairsClass: | |
| // CHECK-REG: SpillSize: { DefaultMode:64 TestMode:128 TestMode1:64 TestMode2:64 } | |
| // CHECK-REG: SpillAlignment: { DefaultMode:32 TestMode:64 TestMode1:32 TestMode2:32 } | |
| // CHECK-REG: CoveredBySubRegs: 1 | |
| // CHECK-REG: Regs: X0_X1 X2_X3 X4_X5 X6_X7 X8_X9 X10_X11 X12_X13 X14_X15 | |
| // CHECK-REG-LABEL: SubRegIndex sub_even: | |
| // CHECK-REG: Offset: { DefaultMode:0 TestMode:0 TestMode1:0 TestMode2:0 } | |
| // CHECK-REG: Size: { DefaultMode:32 TestMode:64 TestMode1:32 TestMode2:32 } | |
| // CHECK-REG-LABEL: SubRegIndex sub_odd: | |
| // CHECK-REG: Offset: { DefaultMode:32 TestMode:64 TestMode1:32 TestMode2:32 } | |
| // CHECK-REG: Size: { DefaultMode:32 TestMode:64 TestMode1:32 TestMode2:32 } | |
| //============================================================================// | |
| //--------------------- Encoding/Decoding parts ------------------------------// | |
| //============================================================================// | |
| def fooTypeEncDefault : InstructionEncoding { | |
| let Size = 8; | |
| field bits<64> SoftFail = 0; | |
| bits<64> Inst; | |
| bits<8> factor; | |
| let Inst{7...0} = factor; | |
| let Inst{3...2} = 0b10; | |
| let Inst{1...0} = 0b00; | |
| } | |
| def fooTypeEncA : InstructionEncoding { | |
| let Size = 4; | |
| field bits<32> SoftFail = 0; | |
| bits<32> Inst; | |
| bits<8> factor; | |
| let Inst{7...0} = factor; | |
| let Inst{3...2} = 0b11; | |
| let Inst{1...0} = 0b00; | |
| } | |
| def foo : Instruction { | |
| bits<32> Inst; | |
| let OutOperandList = (outs); | |
| let InOperandList = (ins i32imm:$factor); | |
| let EncodingInfos = EncodingByHwMode< | |
| [TestMode2, DefaultMode], [fooTypeEncA, fooTypeEncDefault] | |
| >; | |
| let AsmString = "foo $factor"; | |
| } | |
| // CHECK-SUBTARGET-LABEL: unsigned TestTargetGenMCSubtargetInfo::getHwModeSet() const { | |
| // CHECK-SUBTARGET{LITERAL}:[[maybe_unused]] const FeatureBitset &FB = getFeatureBits(); | |
| // CHECK-SUBTARGET-NEXT: // Collect HwModes and store them as a bit set. | |
| // CHECK-SUBTARGET-NEXT: unsigned Modes = 0; | |
| // CHECK-SUBTARGET-NEXT: if (FB[TestTarget::Feat1]) Modes |= (1 << 0); | |
| // CHECK-SUBTARGET-NEXT: if (FB[TestTarget::Feat2]) Modes |= (1 << 1); | |
| // CHECK-SUBTARGET-NEXT: if (FB[TestTarget::Feat1] && FB[TestTarget::Feat2]) Modes |= (1 << 2); | |
| // CHECK-SUBTARGET-NEXT: return Modes; | |
| // CHECK-SUBTARGET-NEXT: } | |
| // CHECK-SUBTARGET-LABEL: unsigned TestTargetGenSubtargetInfo::getHwModeSet() const { | |
| // CHECK-SUBTARGET{LITERAL}:[[maybe_unused]] const auto *Subtarget = | |
| // CHECK-SUBTARGET-NEXT: static_cast<const TestTargetSubtarget *>(this); | |
| // CHECK-SUBTARGET-NEXT: // Collect HwModes and store them as a bit set. | |
| // CHECK-SUBTARGET-NEXT: unsigned Modes = 0; | |
| // CHECK-SUBTARGET-NEXT: if ((Subtarget->hasFeat1())) Modes |= (1 << 0); | |
| // CHECK-SUBTARGET-NEXT: if ((Subtarget->hasFeat2())) Modes |= (1 << 1); | |
| // CHECK-SUBTARGET-NEXT: if ((Subtarget->hasFeat1()) && (Subtarget->hasFeat2())) Modes |= (1 << 2); | |
| // CHECK-SUBTARGET-NEXT: return Modes; | |
| // CHECK-SUBTARGET-NEXT: } | |
| // CHECK-SUBTARGET-LABEL: unsigned TestTargetGenSubtargetInfo::getHwMode(enum HwModeType type) const { | |
| // CHECK-SUBTARGET: unsigned Modes = getHwModeSet(); | |
| // CHECK-SUBTARGET: if (!Modes) | |
| // CHECK-SUBTARGET: return Modes; | |
| // CHECK-SUBTARGET: switch (type) { | |
| // CHECK-SUBTARGET: case HwMode_Default: | |
| // CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1; | |
| // CHECK-SUBTARGET: case HwMode_ValueType: | |
| // CHECK-SUBTARGET: Modes &= 3; | |
| // CHECK-SUBTARGET: if (!Modes) | |
| // CHECK-SUBTARGET: return Modes; | |
| // CHECK-SUBTARGET: if (!llvm::has_single_bit<unsigned>(Modes)) | |
| // CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for ValueType were found!"); | |
| // CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1; | |
| // CHECK-SUBTARGET: case HwMode_RegInfo: | |
| // CHECK-SUBTARGET: Modes &= 1; | |
| // CHECK-SUBTARGET: if (!Modes) | |
| // CHECK-SUBTARGET: return Modes; | |
| // CHECK-SUBTARGET: if (!llvm::has_single_bit<unsigned>(Modes)) | |
| // CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for RegInfo were found!"); | |
| // CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1; | |
| // CHECK-SUBTARGET: case HwMode_EncodingInfo: | |
| // CHECK-SUBTARGET: Modes &= 4; | |
| // CHECK-SUBTARGET: if (!Modes) | |
| // CHECK-SUBTARGET: return Modes; | |
| // CHECK-SUBTARGET: if (!llvm::has_single_bit<unsigned>(Modes)) | |
| // CHECK-SUBTARGET: llvm_unreachable("Two or more HwModes for EncodingInfo were found!"); | |
| // CHECK-SUBTARGET: return llvm::countr_zero(Modes) + 1; | |
| // CHECK-SUBTARGET: } | |
| // CHECK-SUBTARGET: llvm_unreachable("unexpected HwModeType"); | |
| // CHECK-SUBTARGET: return 0; // should not get here | |
| // CHECK-SUBTARGET: } |