[llvm] [X86][GlobalISel] Added support for llvm.set.rounding (PR #156591)

Evgenii Kudriashov via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 16 02:52:11 PDT 2025


================
@@ -858,6 +862,135 @@ bool X86LegalizerInfo::legalizeGETROUNDING(MachineInstr &MI,
   return true;
 }
 
+bool X86LegalizerInfo::legalizeSETROUNDING(MachineInstr &MI,
+                                           MachineRegisterInfo &MRI,
+                                           LegalizerHelper &Helper) const {
+  MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
+  MachineFunction &MF = MIRBuilder.getMF();
+  Register Src = MI.getOperand(0).getReg();
+  const LLT s8 = LLT::scalar(8);
+  const LLT s16 = LLT::scalar(16);
+  const LLT s32 = LLT::scalar(32);
+
+  // Allocate stack slot for control word and MXCSR (4 bytes).
+  int MemSize = 4;
+  Align Alignment = Align(4);
+  MachinePointerInfo PtrInfo;
+  auto StackTemp = Helper.createStackTemporary(TypeSize::getFixed(MemSize),
+                                               Alignment, PtrInfo);
+  Register StackPtr = StackTemp.getReg(0);
+
+  auto StoreMMO =
+      MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore, 2, Align(2));
+  MIRBuilder.buildInstr(X86::G_FNSTCW16)
+      .addUse(StackPtr)
+      .addMemOperand(StoreMMO);
+
+  auto LoadMMO =
+      MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad, 2, Align(2));
+  auto CWD16 = MIRBuilder.buildLoad(s16, StackPtr, *LoadMMO);
+
+  // Clear RM field (bits 11:10)
+  auto ClearedCWD =
+      MIRBuilder.buildAnd(s16, CWD16, MIRBuilder.buildConstant(s16, 0xf3ff));
+
+  // Check if Src is a constant
+  auto *SrcDef = MRI.getVRegDef(Src);
+  Register RMBits;
+  if (SrcDef && SrcDef->getOpcode() == TargetOpcode::G_CONSTANT) {
+    uint64_t RM = getIConstantFromReg(Src, MRI).getZExtValue();
+    int FieldVal;
+    switch (static_cast<RoundingMode>(RM)) {
+    case RoundingMode::NearestTiesToEven:
+      FieldVal = X86::rmToNearest;
+      break;
+    case RoundingMode::TowardNegative:
+      FieldVal = X86::rmDownward;
+      break;
+    case RoundingMode::TowardPositive:
+      FieldVal = X86::rmUpward;
+      break;
+    case RoundingMode::TowardZero:
+      FieldVal = X86::rmTowardZero;
+      break;
+    default:
+      report_fatal_error("rounding mode is not supported by X86 hardware");
+    }
+    RMBits = MIRBuilder.buildConstant(s16, FieldVal).getReg(0);
+  } else {
+    // Convert Src (rounding mode) to bits for control word
+    // (0xc9 << (2 * Src + 4)) & 0xc00
+    auto Src32 = MIRBuilder.buildZExtOrTrunc(s32, Src);
+    auto ShiftAmt = MIRBuilder.buildAdd(
+        s32, MIRBuilder.buildShl(s32, Src32, MIRBuilder.buildConstant(s32, 1)),
+        MIRBuilder.buildConstant(s32, 4));
+    auto ShiftAmt8 = MIRBuilder.buildTrunc(s8, ShiftAmt);
+    auto Shifted = MIRBuilder.buildShl(s16, MIRBuilder.buildConstant(s16, 0xc9),
+                                       ShiftAmt8);
+    RMBits =
+        MIRBuilder.buildAnd(s16, Shifted, MIRBuilder.buildConstant(s16, 0xc00))
+            .getReg(0);
+  }
+  // Update rounding mode bits
+  auto NewCWD =
+      MIRBuilder.buildOr(s16, ClearedCWD, RMBits, MachineInstr::Disjoint);
+
+  // Store new FP Control Word to stack
+  auto StoreNewMMO =
+      MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore, 2, Align(2));
+  MIRBuilder.buildStore(NewCWD, StackPtr, *StoreNewMMO);
+
+  // Load FP control word from the slot using G_FLDCW16
+  auto LoadNewMMO =
+      MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad, 2, Align(2));
+  MIRBuilder.buildInstr(X86::G_FLDCW16)
+      .addUse(StackPtr)
+      .addMemOperand(LoadNewMMO);
+
+  if (Subtarget.hasSSE1()) {
+    // Store MXCSR to stack (use STMXCSR)
+    auto StoreMXCSRMMO = MF.getMachineMemOperand(
+        PtrInfo, MachineMemOperand::MOStore, 4, Align(4));
+    MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS)
+        .addIntrinsicID(Intrinsic::x86_sse_stmxcsr)
+        .addUse(StackPtr)
+        .addMemOperand(StoreMXCSRMMO);
+
+    // Load MXCSR from stack
+    auto LoadMXCSRMMO = MF.getMachineMemOperand(
+        PtrInfo, MachineMemOperand::MOLoad, 4, Align(4));
+    auto MXCSR = MIRBuilder.buildLoad(s32, StackPtr, *LoadMXCSRMMO);
+
+    // Clear RM field (bits 14:13)
+    auto ClearedMXCSR = MIRBuilder.buildAnd(
+        s32, MXCSR, MIRBuilder.buildConstant(s32, 0xffff9fff));
+
+    // Shift x87 RM bits from 11:10 to 14:13
+    auto RMBits32 = MIRBuilder.buildZExt(s32, RMBits);
+    auto MXCSRRMBits =
+        MIRBuilder.buildShl(s32, RMBits32, MIRBuilder.buildConstant(s32, 3));
----------------
e-kud wrote:

Let's add do this shift during compilation for constant input instead of using a combine.

https://github.com/llvm/llvm-project/pull/156591


More information about the llvm-commits mailing list