[llvm] [BOLT] Optimize the codegen of createLoadImmediate for AArch64. (PR #137413)

Rodrigo Rocha via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 28 13:11:24 PDT 2025


https://github.com/rcorcs updated https://github.com/llvm/llvm-project/pull/137413

>From df903ac5d1894a41ddefde98d701828fad60a409 Mon Sep 17 00:00:00 2001
From: Rodrigo Rocha <rcor.cs at gmail.com>
Date: Fri, 25 Apr 2025 23:51:12 +0100
Subject: [PATCH 1/2] Optimize the code generation of createLoadImmediate for
 AArch64.

---
 .../Target/AArch64/AArch64MCPlusBuilder.cpp   | 28 +++++--
 bolt/unittests/Core/MCPlusBuilder.cpp         | 84 +++++++++++++++++++
 2 files changed, 104 insertions(+), 8 deletions(-)

diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
index e00d6a18b0f6c..0aa9504f50a15 100644
--- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
@@ -2173,14 +2173,26 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
 
   InstructionListType createLoadImmediate(const MCPhysReg Dest,
                                           uint64_t Imm) const override {
-    InstructionListType Insts(4);
-    int Shift = 48;
-    for (int I = 0; I < 4; I++, Shift -= 16) {
-      Insts[I].setOpcode(AArch64::MOVKXi);
-      Insts[I].addOperand(MCOperand::createReg(Dest));
-      Insts[I].addOperand(MCOperand::createReg(Dest));
-      Insts[I].addOperand(MCOperand::createImm((Imm >> Shift) & 0xFFFF));
-      Insts[I].addOperand(MCOperand::createImm(Shift));
+    InstructionListType Insts;
+    for (int I = 0, Shift = 0; I < 4; I++, Shift += 16) {
+      uint16_t HalfWord = (Imm >> Shift) & 0xFFFF;
+      if (!HalfWord)
+        continue;
+      MCInst Inst;
+      if (Insts.size() == 0) {
+        Inst.setOpcode(AArch64::MOVZXi);
+        Inst.addOperand(MCOperand::createReg(Dest));
+        Inst.addOperand(MCOperand::createImm(HalfWord));
+        Inst.addOperand(MCOperand::createImm(Shift));
+        Insts.push_back(Inst);
+      } else {
+        Inst.setOpcode(AArch64::MOVKXi);
+        Inst.addOperand(MCOperand::createReg(Dest));
+        Inst.addOperand(MCOperand::createReg(Dest));
+        Inst.addOperand(MCOperand::createImm(HalfWord));
+        Inst.addOperand(MCOperand::createImm(Shift));
+        Insts.push_back(Inst);
+      }
     }
     return Insts;
   }
diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp
index 7016dec0e3574..ac0529cb09a7b 100644
--- a/bolt/unittests/Core/MCPlusBuilder.cpp
+++ b/bolt/unittests/Core/MCPlusBuilder.cpp
@@ -167,6 +167,90 @@ TEST_P(MCPlusBuilderTester, AArch64_CmpJNE) {
   ASSERT_EQ(Label, BB->getLabel());
 }
 
+TEST_P(MCPlusBuilderTester, AArch64_LoadImm32) {
+  if (GetParam() != Triple::aarch64)
+    GTEST_SKIP();
+  BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
+  std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
+
+  InstructionListType Instrs = BC->MIB->createLoadImmediate(AArch64::X0, 2);
+  BB->addInstructions(Instrs.begin(), Instrs.end());
+
+  ASSERT_EQ(BB->size(), 1);
+  auto II = BB->begin();
+  // mov x0, #2
+  ASSERT_EQ(II->getOpcode(), AArch64::MOVZXi);
+  ASSERT_EQ(II->getOperand(0).getReg(), AArch64::X0);
+  ASSERT_EQ(II->getOperand(1).getImm(), 2);
+  ASSERT_EQ(II->getOperand(2).getImm(), 0);
+}
+
+TEST_P(MCPlusBuilderTester, AArch64_LoadImm64) {
+  if (GetParam() != Triple::aarch64)
+    GTEST_SKIP();
+  BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
+  std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
+
+  int64_t Imm = ((uint64_t)4) << 48 | ((uint64_t)3) << 32 | 2 << 16 | 1;
+  InstructionListType Instrs = BC->MIB->createLoadImmediate(AArch64::X0, Imm);
+  BB->addInstructions(Instrs.begin(), Instrs.end());
+
+  ASSERT_EQ(BB->size(), 4);
+  auto II = BB->begin();
+  // mov x0, #1
+  ASSERT_EQ(II->getOpcode(), AArch64::MOVZXi);
+  ASSERT_EQ(II->getOperand(0).getReg(), AArch64::X0);
+  ASSERT_EQ(II->getOperand(1).getImm(), 1);
+  ASSERT_EQ(II->getOperand(2).getImm(), 0);
+  II++;
+  // movk x0, #2, lsl #16
+  ASSERT_EQ(II->getOpcode(), AArch64::MOVKXi);
+  ASSERT_EQ(II->getOperand(0).getReg(), AArch64::X0);
+  ASSERT_EQ(II->getOperand(1).getReg(), AArch64::X0);
+  ASSERT_EQ(II->getOperand(2).getImm(), 2);
+  ASSERT_EQ(II->getOperand(3).getImm(), 16);
+  II++;
+  // movk x0, #3, lsl #32
+  ASSERT_EQ(II->getOpcode(), AArch64::MOVKXi);
+  ASSERT_EQ(II->getOperand(0).getReg(), AArch64::X0);
+  ASSERT_EQ(II->getOperand(1).getReg(), AArch64::X0);
+  ASSERT_EQ(II->getOperand(2).getImm(), 3);
+  ASSERT_EQ(II->getOperand(3).getImm(), 32);
+  II++;
+  // movk x0, #4, lsl #48
+  ASSERT_EQ(II->getOpcode(), AArch64::MOVKXi);
+  ASSERT_EQ(II->getOperand(0).getReg(), AArch64::X0);
+  ASSERT_EQ(II->getOperand(1).getReg(), AArch64::X0);
+  ASSERT_EQ(II->getOperand(2).getImm(), 4);
+  ASSERT_EQ(II->getOperand(3).getImm(), 48);
+}
+
+TEST_P(MCPlusBuilderTester, AArch64_LoadImm64Partial) {
+  if (GetParam() != Triple::aarch64)
+    GTEST_SKIP();
+  BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
+  std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
+
+  int64_t Imm = ((uint64_t)4) << 48 | 2 << 16;
+  InstructionListType Instrs = BC->MIB->createLoadImmediate(AArch64::X0, Imm);
+  BB->addInstructions(Instrs.begin(), Instrs.end());
+
+  ASSERT_EQ(BB->size(), 2);
+  auto II = BB->begin();
+  // mov x0, #2, lsl #16
+  ASSERT_EQ(II->getOpcode(), AArch64::MOVZXi);
+  ASSERT_EQ(II->getOperand(0).getReg(), AArch64::X0);
+  ASSERT_EQ(II->getOperand(1).getImm(), 2);
+  ASSERT_EQ(II->getOperand(2).getImm(), 16);
+  II++;
+  // movk x0, #4, lsl #48
+  ASSERT_EQ(II->getOpcode(), AArch64::MOVKXi);
+  ASSERT_EQ(II->getOperand(0).getReg(), AArch64::X0);
+  ASSERT_EQ(II->getOperand(1).getReg(), AArch64::X0);
+  ASSERT_EQ(II->getOperand(2).getImm(), 4);
+  ASSERT_EQ(II->getOperand(3).getImm(), 48);
+}
+
 TEST_P(MCPlusBuilderTester, testAccessedRegsImplicitDef) {
   if (GetParam() != Triple::aarch64)
     GTEST_SKIP();

>From 3721648acb6e549265945124653641b773c5848b Mon Sep 17 00:00:00 2001
From: Rodrigo Rocha <rcor.cs at gmail.com>
Date: Mon, 28 Apr 2025 21:10:47 +0100
Subject: [PATCH 2/2] [BOLT] Fixed createLoadImmediate when Imm=0

---
 .../Target/AArch64/AArch64MCPlusBuilder.cpp   | 44 ++++++++++++-------
 bolt/unittests/Core/MCPlusBuilder.cpp         | 21 ++++++++-
 2 files changed, 47 insertions(+), 18 deletions(-)

diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
index 0aa9504f50a15..1ac6001d428cc 100644
--- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
+++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp
@@ -2174,24 +2174,34 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
   InstructionListType createLoadImmediate(const MCPhysReg Dest,
                                           uint64_t Imm) const override {
     InstructionListType Insts;
-    for (int I = 0, Shift = 0; I < 4; I++, Shift += 16) {
-      uint16_t HalfWord = (Imm >> Shift) & 0xFFFF;
-      if (!HalfWord)
-        continue;
+    if (Imm == 0) {
       MCInst Inst;
-      if (Insts.size() == 0) {
-        Inst.setOpcode(AArch64::MOVZXi);
-        Inst.addOperand(MCOperand::createReg(Dest));
-        Inst.addOperand(MCOperand::createImm(HalfWord));
-        Inst.addOperand(MCOperand::createImm(Shift));
-        Insts.push_back(Inst);
-      } else {
-        Inst.setOpcode(AArch64::MOVKXi);
-        Inst.addOperand(MCOperand::createReg(Dest));
-        Inst.addOperand(MCOperand::createReg(Dest));
-        Inst.addOperand(MCOperand::createImm(HalfWord));
-        Inst.addOperand(MCOperand::createImm(Shift));
-        Insts.push_back(Inst);
+      Inst.setOpcode(AArch64::ORRXrs);
+      Inst.addOperand(MCOperand::createReg(Dest));
+      Inst.addOperand(MCOperand::createReg(AArch64::XZR));
+      Inst.addOperand(MCOperand::createReg(AArch64::XZR));
+      Inst.addOperand(MCOperand::createImm(0));
+      Insts.push_back(Inst);
+    } else {
+      for (int I = 0, Shift = 0; I < 4; I++, Shift += 16) {
+        uint16_t HalfWord = (Imm >> Shift) & 0xFFFF;
+        if (!HalfWord)
+          continue;
+        MCInst Inst;
+        if (Insts.size() == 0) {
+          Inst.setOpcode(AArch64::MOVZXi);
+          Inst.addOperand(MCOperand::createReg(Dest));
+          Inst.addOperand(MCOperand::createImm(HalfWord));
+          Inst.addOperand(MCOperand::createImm(Shift));
+          Insts.push_back(Inst);
+        } else {
+          Inst.setOpcode(AArch64::MOVKXi);
+          Inst.addOperand(MCOperand::createReg(Dest));
+          Inst.addOperand(MCOperand::createReg(Dest));
+          Inst.addOperand(MCOperand::createImm(HalfWord));
+          Inst.addOperand(MCOperand::createImm(Shift));
+          Insts.push_back(Inst);
+        }
       }
     }
     return Insts;
diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp
index ac0529cb09a7b..326d484f0a39e 100644
--- a/bolt/unittests/Core/MCPlusBuilder.cpp
+++ b/bolt/unittests/Core/MCPlusBuilder.cpp
@@ -167,7 +167,26 @@ TEST_P(MCPlusBuilderTester, AArch64_CmpJNE) {
   ASSERT_EQ(Label, BB->getLabel());
 }
 
-TEST_P(MCPlusBuilderTester, AArch64_LoadImm32) {
+TEST_P(MCPlusBuilderTester, AArch64_LoadZero) {
+  if (GetParam() != Triple::aarch64)
+    GTEST_SKIP();
+  BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);
+  std::unique_ptr<BinaryBasicBlock> BB = BF->createBasicBlock();
+
+  InstructionListType Instrs = BC->MIB->createLoadImmediate(AArch64::X0, 0);
+  BB->addInstructions(Instrs.begin(), Instrs.end());
+
+  ASSERT_EQ(BB->size(), 1);
+  auto II = BB->begin();
+  // mov x0, xzr <=> orr x0, xzr, xzr, lsl #0
+  ASSERT_EQ(II->getOpcode(), AArch64::ORRXrs);
+  ASSERT_EQ(II->getOperand(0).getReg(), AArch64::X0);
+  ASSERT_EQ(II->getOperand(1).getReg(), AArch64::XZR);
+  ASSERT_EQ(II->getOperand(2).getReg(), AArch64::XZR);
+  ASSERT_EQ(II->getOperand(3).getImm(), 0);
+}
+
+TEST_P(MCPlusBuilderTester, AArch64_LoadImm16) {
   if (GetParam() != Triple::aarch64)
     GTEST_SKIP();
   BinaryFunction *BF = BC->createInjectedBinaryFunction("BF", true);



More information about the llvm-commits mailing list