@@ -898,7 +898,9 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
898
898
getActionDefinitionsBuilder ({G_UADDSAT, G_USUBSAT})
899
899
.lowerIf ([=](const LegalityQuery &Q) { return Q.Types [0 ].isScalar (); });
900
900
901
- getActionDefinitionsBuilder ({G_FSHL, G_FSHR}).lower ();
901
+ getActionDefinitionsBuilder ({G_FSHL, G_FSHR})
902
+ .customFor ({{s32, s32}, {s32, s64}, {s64, s64}})
903
+ .lower ();
902
904
903
905
getActionDefinitionsBuilder (G_ROTR)
904
906
.legalFor ({{s32, s64}, {s64, s64}})
@@ -1003,6 +1005,9 @@ bool AArch64LegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
1003
1005
case TargetOpcode::G_SBFX:
1004
1006
case TargetOpcode::G_UBFX:
1005
1007
return legalizeBitfieldExtract (MI, MRI, Helper);
1008
+ case TargetOpcode::G_FSHL:
1009
+ case TargetOpcode::G_FSHR:
1010
+ return legalizeFunnelShift (MI, MRI, MIRBuilder, Observer, Helper);
1006
1011
case TargetOpcode::G_ROTR:
1007
1012
return legalizeRotate (MI, MRI, Helper);
1008
1013
case TargetOpcode::G_CTPOP:
@@ -1023,6 +1028,59 @@ bool AArch64LegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
1023
1028
llvm_unreachable (" expected switch to return" );
1024
1029
}
1025
1030
1031
+ bool AArch64LegalizerInfo::legalizeFunnelShift (MachineInstr &MI,
1032
+ MachineRegisterInfo &MRI,
1033
+ MachineIRBuilder &MIRBuilder,
1034
+ GISelChangeObserver &Observer,
1035
+ LegalizerHelper &Helper) const {
1036
+ assert (MI.getOpcode () == TargetOpcode::G_FSHL ||
1037
+ MI.getOpcode () == TargetOpcode::G_FSHR);
1038
+
1039
+ // Keep as G_FSHR if shift amount is a G_CONSTANT, else use generic
1040
+ // lowering
1041
+ Register ShiftNo = MI.getOperand (3 ).getReg ();
1042
+ LLT ShiftTy = MRI.getType (ShiftNo);
1043
+ auto VRegAndVal = getIConstantVRegValWithLookThrough (ShiftNo, MRI);
1044
+
1045
+ // Adjust shift amount according to Opcode (FSHL/FSHR)
1046
+ // Convert FSHL to FSHR
1047
+ LLT OperationTy = MRI.getType (MI.getOperand (0 ).getReg ());
1048
+ APInt BitWidth (ShiftTy.getSizeInBits (), OperationTy.getSizeInBits (), false );
1049
+
1050
+ // Lower non-constant shifts and leave zero shifts to the optimizer.
1051
+ if (!VRegAndVal || VRegAndVal->Value .urem (BitWidth) == 0 )
1052
+ return (Helper.lowerFunnelShiftAsShifts (MI) ==
1053
+ LegalizerHelper::LegalizeResult::Legalized);
1054
+
1055
+ APInt Amount = VRegAndVal->Value .urem (BitWidth);
1056
+
1057
+ Amount = MI.getOpcode () == TargetOpcode::G_FSHL ? BitWidth - Amount : Amount;
1058
+
1059
+ // If the instruction is G_FSHR, has a 64-bit G_CONSTANT for shift amount
1060
+ // in the range of 0 <-> BitWidth, it is legal
1061
+ if (ShiftTy.getSizeInBits () == 64 && MI.getOpcode () == TargetOpcode::G_FSHR &&
1062
+ VRegAndVal->Value .ult (BitWidth))
1063
+ return true ;
1064
+
1065
+ // Cast the ShiftNumber to a 64-bit type
1066
+ auto Cast64 = MIRBuilder.buildConstant (LLT::scalar (64 ), Amount.zext (64 ));
1067
+
1068
+ if (MI.getOpcode () == TargetOpcode::G_FSHR) {
1069
+ Observer.changingInstr (MI);
1070
+ MI.getOperand (3 ).setReg (Cast64.getReg (0 ));
1071
+ Observer.changedInstr (MI);
1072
+ }
1073
+ // If Opcode is FSHL, remove the FSHL instruction and create a FSHR
1074
+ // instruction
1075
+ else if (MI.getOpcode () == TargetOpcode::G_FSHL) {
1076
+ MIRBuilder.buildInstr (TargetOpcode::G_FSHR, {MI.getOperand (0 ).getReg ()},
1077
+ {MI.getOperand (1 ).getReg (), MI.getOperand (2 ).getReg (),
1078
+ Cast64.getReg (0 )});
1079
+ MI.eraseFromParent ();
1080
+ }
1081
+ return true ;
1082
+ }
1083
+
1026
1084
bool AArch64LegalizerInfo::legalizeRotate (MachineInstr &MI,
1027
1085
MachineRegisterInfo &MRI,
1028
1086
LegalizerHelper &Helper) const {
0 commit comments