From dd88f40c80f54e5f66b5ead1787f88c376b61d8a Mon Sep 17 00:00:00 2001 From: tyb0807 Date: Sat, 22 Jan 2022 10:31:56 +0000 Subject: [PATCH] [AArch64] Make getInstSizeInBytes() use instruction size from InstrInfo.td Currently, AArch64InstrInfo::getInstSizeInBytes() uses hard-coded instruction size for some pseudo-instructions, while this information should ideally be found in AArch64InstrInfo.td file (which can be accessed via MCInstrDesc). Hence, the .td file should be updated and no hard-coded instruction sizes should be used by getInstSizeInBytes() anymore. Differential Revision: https://reviews.llvm.org/D117970 --- llvm/lib/Target/AArch64/AArch64InstrInfo.cpp | 35 ++---- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 12 +- llvm/unittests/Target/AArch64/InstSizes.cpp | 112 ++++++++++++++++++- 3 files changed, 128 insertions(+), 31 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp index c3ccc541c0b8..a9191924129c 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp @@ -93,9 +93,18 @@ unsigned AArch64InstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { // before the assembly printer. unsigned NumBytes = 0; const MCInstrDesc &Desc = MI.getDesc(); + + // Size should be preferably set in + // llvm/lib/Target/AArch64/AArch64InstrInfo.td (default case). + // Specific cases handle instructions of variable sizes switch (Desc.getOpcode()) { default: - // Anything not explicitly designated otherwise is a normal 4-byte insn. + if (Desc.getSize()) + return Desc.getSize(); + + // Anything not explicitly designated otherwise (i.e. pseudo-instructions + // with fixed constant size but not specified in .td file) is a normal + // 4-byte insn. NumBytes = 4; break; case TargetOpcode::STACKMAP: @@ -115,33 +124,9 @@ unsigned AArch64InstrInfo::getInstSizeInBytes(const MachineInstr &MI) const { if (NumBytes == 0) NumBytes = 4; break; - case AArch64::TLSDESC_CALLSEQ: - // This gets lowered to an instruction sequence which takes 16 bytes - NumBytes = 16; - break; - case AArch64::SpeculationBarrierISBDSBEndBB: - // This gets lowered to 2 4-byte instructions. - NumBytes = 8; - break; - case AArch64::SpeculationBarrierSBEndBB: - // This gets lowered to 1 4-byte instructions. - NumBytes = 4; - break; - case AArch64::JumpTableDest32: - case AArch64::JumpTableDest16: - case AArch64::JumpTableDest8: - case AArch64::MOPSMemoryCopyPseudo: - case AArch64::MOPSMemoryMovePseudo: - case AArch64::MOPSMemorySetPseudo: - case AArch64::MOPSMemorySetTaggingPseudo: - NumBytes = 12; - break; case AArch64::SPACE: NumBytes = MI.getOperand(1).getImm(); break; - case AArch64::StoreSwiftAsyncContext: - NumBytes = 20; - break; case TargetOpcode::BUNDLE: NumBytes = getInstBundleLength(MI); break; diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index daceb3feffa3..83bf89ff97c5 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -780,6 +780,7 @@ def : Pat<(AArch64LOADgot texternalsym:$addr), def : Pat<(AArch64LOADgot tconstpool:$addr), (LOADgot tconstpool:$addr)>; +// In general these get lowered into a sequence of three 4-byte instructions. // 32-bit jump table destination is actually only 2 instructions since we can // use the table itself as a PC-relative base. But optimization occurs after // branch relaxation so be pessimistic. @@ -815,8 +816,12 @@ let hasSideEffects = 1, isCodeGenOnly = 1 in { // SpeculationBarrierEndBB must only be used after an unconditional control // flow, i.e. after a terminator for which isBarrier is True. let hasSideEffects = 1, isCodeGenOnly = 1, isTerminator = 1, isBarrier = 1 in { + // This gets lowered to a pair of 4-byte instructions. + let Size = 8 in def SpeculationBarrierISBDSBEndBB : Pseudo<(outs), (ins), []>, Sched<[]>; + // This gets lowered to a 4-byte instruction. + let Size = 4 in def SpeculationBarrierSBEndBB : Pseudo<(outs), (ins), []>, Sched<[]>; } @@ -2356,7 +2361,8 @@ def EMITBKEY : Pseudo<(outs), (ins), []>, Sched<[]> {} // FIXME: maybe the scratch register used shouldn't be fixed to X1? // FIXME: can "hasSideEffects be dropped? -let isCall = 1, Defs = [LR, X0, X1], hasSideEffects = 1, +// This gets lowered to an instruction sequence which takes 16 bytes +let isCall = 1, Defs = [LR, X0, X1], hasSideEffects = 1, Size = 16, isCodeGenOnly = 1 in def TLSDESC_CALLSEQ : Pseudo<(outs), (ins i64imm:$sym), @@ -8370,6 +8376,7 @@ def AArch64mops_memset_tagging : SDNode<"AArch64ISD::MOPS_MEMSET_TAGGING", SDT_A def AArch64mops_memcopy : SDNode<"AArch64ISD::MOPS_MEMCOPY", SDT_AArch64mops>; def AArch64mops_memmove : SDNode<"AArch64ISD::MOPS_MEMMOVE", SDT_AArch64mops>; +// MOPS operations always contain three 4-byte instructions let Predicates = [HasMOPS], Defs = [NZCV], Size = 12, mayStore = 1 in { let mayLoad = 1 in { def MOPSMemoryCopyPseudo : Pseudo<(outs GPR64common:$Rd_wb, GPR64common:$Rs_wb, GPR64:$Rn_wb), @@ -8391,7 +8398,8 @@ let Predicates = [HasMOPS, HasMTE], Defs = [NZCV], Size = 12, mayLoad = 0, maySt [], "$Rd = $Rd_wb,$Rn = $Rn_wb">, Sched<[]>; } -let Defs = [X16, X17], mayStore = 1, isCodeGenOnly = 1 in +// This gets lowered into an instruction sequence of 20 bytes +let Defs = [X16, X17], mayStore = 1, isCodeGenOnly = 1, Size = 20 in def StoreSwiftAsyncContext : Pseudo<(outs), (ins GPR64:$ctx, GPR64sp:$base, simm9:$offset), []>, Sched<[]>; diff --git a/llvm/unittests/Target/AArch64/InstSizes.cpp b/llvm/unittests/Target/AArch64/InstSizes.cpp index 540e248bad6e..f17290c73ee5 100644 --- a/llvm/unittests/Target/AArch64/InstSizes.cpp +++ b/llvm/unittests/Target/AArch64/InstSizes.cpp @@ -52,6 +52,11 @@ void runChecks( "...\n" "---\n" "name: sizes\n" + "jumpTable:\n" + " kind: block-address\n" + " entries:\n" + " - id: 0\n" + " blocks: [ '%bb.0' ]\n" "body: |\n" " bb.0:\n" + InputMIRSnippet.str(); @@ -142,6 +147,34 @@ TEST(InstSizes, PATCHPOINT) { }); } +TEST(InstSizes, STATEPOINT) { + std::unique_ptr TM = createTargetMachine(); + std::unique_ptr II = createInstrInfo(TM.get()); + + runChecks(TM.get(), II.get(), "", + " STATEPOINT 0, 0, 0, @sizes, 2, 0, 2, 0, 2, 0, 2, 1, 1, 8," + " $sp, 24, 2, 0, 2, 1, 0, 0\n", + [](AArch64InstrInfo &II, MachineFunction &MF) { + auto I = MF.begin()->begin(); + EXPECT_EQ(4u, II.getInstSizeInBytes(*I)); + }); +} + +TEST(InstSizes, SPACE) { + std::unique_ptr TM = createTargetMachine(); + std::unique_ptr II = createInstrInfo(TM.get()); + + runChecks(TM.get(), II.get(), "", + " $xzr = SPACE 1024, undef $xzr\n" + " dead $xzr = SPACE 4096, $xzr\n", + [](AArch64InstrInfo &II, MachineFunction &MF) { + auto I = MF.begin()->begin(); + EXPECT_EQ(1024u, II.getInstSizeInBytes(*I)); + ++I; + EXPECT_EQ(4096u, II.getInstSizeInBytes(*I)); + }); +} + TEST(InstSizes, TLSDESC_CALLSEQ) { std::unique_ptr TM = createTargetMachine(); std::unique_ptr II = createInstrInfo(TM.get()); @@ -156,16 +189,87 @@ TEST(InstSizes, TLSDESC_CALLSEQ) { }); } -TEST(InstSizes, MOPSMemorySetTaggingPseudo) { +TEST(InstSizes, StoreSwiftAsyncContext) { + std::unique_ptr TM = createTargetMachine(); + std::unique_ptr II = createInstrInfo(TM.get()); + + runChecks( + TM.get(), II.get(), "", + " StoreSwiftAsyncContext $x0, $x1, 12, implicit-def $x16, " + "implicit-def $x17\n", + [](AArch64InstrInfo &II, MachineFunction &MF) { + auto I = MF.begin()->begin(); + EXPECT_EQ(20u, II.getInstSizeInBytes(*I)); + }); +} + +TEST(InstSizes, SpeculationBarrierISBDSBEndBB) { + std::unique_ptr TM = createTargetMachine(); + std::unique_ptr II = createInstrInfo(TM.get()); + + runChecks( + TM.get(), II.get(), "", + " SpeculationBarrierISBDSBEndBB\n" + " BR $x8\n", + [](AArch64InstrInfo &II, MachineFunction &MF) { + auto I = MF.begin()->begin(); + EXPECT_EQ(8u, II.getInstSizeInBytes(*I)); + }); +} + +TEST(InstSizes, SpeculationBarrierSBEndBB) { + std::unique_ptr TM = createTargetMachine(); + std::unique_ptr II = createInstrInfo(TM.get()); + + runChecks( + TM.get(), II.get(), "", + " SpeculationBarrierSBEndBB\n" + " BR $x8\n", + [](AArch64InstrInfo &II, MachineFunction &MF) { + auto I = MF.begin()->begin(); + EXPECT_EQ(4u, II.getInstSizeInBytes(*I)); + }); +} + +TEST(InstSizes, JumpTable) { std::unique_ptr TM = createTargetMachine(); std::unique_ptr II = createInstrInfo(TM.get()); runChecks(TM.get(), II.get(), "", - " renamable $x0, dead renamable $x1 = MOPSMemorySetTaggingPseudo " - "killed renamable $x0, killed renamable $x1, killed renamable $x2, " - "implicit-def dead $nzcv\n", + " $x10, $x11 = JumpTableDest32 $x9, $x8, %jump-table.0\n" + " $x10, $x11 = JumpTableDest16 $x9, $x8, %jump-table.0\n" + " $x10, $x11 = JumpTableDest8 $x9, $x8, %jump-table.0\n", [](AArch64InstrInfo &II, MachineFunction &MF) { auto I = MF.begin()->begin(); EXPECT_EQ(12u, II.getInstSizeInBytes(*I)); + ++I; + EXPECT_EQ(12u, II.getInstSizeInBytes(*I)); + ++I; + EXPECT_EQ(12u, II.getInstSizeInBytes(*I)); + }); +} + +TEST(InstSizes, MOPSMemoryPseudos) { + std::unique_ptr TM = createTargetMachine(); + std::unique_ptr II = createInstrInfo(TM.get()); + + runChecks(TM.get(), II.get(), "", + " $x0, $x1, $x2 = MOPSMemoryMovePseudo $x0, $x1, $x2, " + "implicit-def $nzcv\n" + " $x0, $x1 = MOPSMemorySetPseudo $x0, $x1, $x2, " + "implicit-def $nzcv\n" + " $x0, $x1, $x8 = MOPSMemoryCopyPseudo $x0, $x1, $x8, " + "implicit-def $nzcv\n" + " $x0, $x1 = MOPSMemorySetTaggingPseudo $x0, $x1, $x2, " + "implicit-def $nzcv\n", + [](AArch64InstrInfo &II, MachineFunction &MF) { + auto I = MF.begin()->begin(); + EXPECT_EQ(12u, II.getInstSizeInBytes(*I)); + ++I; + EXPECT_EQ(12u, II.getInstSizeInBytes(*I)); + ++I; + EXPECT_EQ(12u, II.getInstSizeInBytes(*I)); + ++I; + EXPECT_EQ(12u, II.getInstSizeInBytes(*I)); }); }