From 3ce1319788fe58a7de5ffdf604ed9732a0ac2697 Mon Sep 17 00:00:00 2001 From: Lucas Date: Wed, 21 Feb 2024 14:27:10 -0300 Subject: [PATCH] Generate explicit sign extension --- llvm/lib/Target/SBF/SBFInstrInfo.td | 34 +++++++++++--- llvm/lib/Target/SBF/SBFMIPeephole.cpp | 6 ++- llvm/lib/Target/SBF/SBFSubtarget.cpp | 1 + llvm/lib/Target/SBF/SBFSubtarget.h | 4 ++ llvm/lib/Target/SBF/SBFTargetFeatures.td | 5 +- llvm/test/CodeGen/SBF/explicit-sext.ll | 60 ++++++++++++++++++++++++ 6 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 llvm/test/CodeGen/SBF/explicit-sext.ll diff --git a/llvm/lib/Target/SBF/SBFInstrInfo.td b/llvm/lib/Target/SBF/SBFInstrInfo.td index 4bc620a97e81ba..63aac4979847b8 100644 --- a/llvm/lib/Target/SBF/SBFInstrInfo.td +++ b/llvm/lib/Target/SBF/SBFInstrInfo.td @@ -65,6 +65,8 @@ def SBFCallxSrc : Predicate<"Subtarget->getCallXRegSrc()">, AssemblerPredicate<( def SBFNoCallxSrc : Predicate<"!Subtarget->getCallXRegSrc()">; def SBFPqrInstr : Predicate<"Subtarget->getHasPqrClass()">; def SBFNoPqrInstr : Predicate<"!Subtarget->getHasPqrClass()">; +def SBFExplicitSext : Predicate<"Subtarget->getExplicitSignExt()">; +def SBFNoExplicitSext : Predicate<"!Subtarget->getExplicitSignExt()">; def brtarget : Operand { let PrintMethod = "printBrTargetOperand"; @@ -968,14 +970,34 @@ def : Pat<(SBFWrapper tglobaladdr:$in), tglobaladdr:$in)>, Requires<[SBFNoLddw]>; -def : Pat<(i64 (sext GPR32:$src)), - (SRA_ri (SLL_ri (MOV_32_64 GPR32:$src), 32), 32)>; +let Predicates = [SBFNoExplicitSext] in { + def : Pat<(i64 (sext GPR32:$src)), + (SRA_ri (SLL_ri (MOV_32_64 GPR32:$src), 32), 32)>; -def : Pat<(i64 (zext GPR32:$src)), (MOV_32_64 GPR32:$src)>; + def : Pat<(i64 (zext GPR32:$src)), (MOV_32_64 GPR32:$src)>; + + // For i64 -> i32 truncation, use the 32-bit subregister directly. + def : Pat<(i32 (trunc GPR:$src)), + (i32 (EXTRACT_SUBREG GPR:$src, sub_32))>; +} + +let Predicates = [SBFExplicitSext] in { + def : Pat<(i64 (sext GPR32:$src)), + (MOV_32_64 GPR32:$src)>; + + // For zero extending, we use a mask to remove potential + // high bits from 'mov32 reg, reg'. + def : Pat<(i64 (zext GPR32:$src)), + (INSERT_SUBREG (i64 (IMPLICIT_DEF)), + (AND_ri_32 GPR32:$src, 0xffffffff), sub_32)>; + + // For truncation, we need a bit mask before placing the value + // in a subregister. + def : Pat<(i32 (trunc GPR:$src)), + (AND_ri_32 (i32 (EXTRACT_SUBREG GPR:$src, sub_32)), + 0xffffffff)>; +} -// For i64 -> i32 truncation, use the 32-bit subregister directly. -def : Pat<(i32 (trunc GPR:$src)), - (i32 (EXTRACT_SUBREG GPR:$src, sub_32))>; // For i32 -> i64 anyext, we don't care about the high bits. def : Pat<(i64 (anyext GPR32:$src)), diff --git a/llvm/lib/Target/SBF/SBFMIPeephole.cpp b/llvm/lib/Target/SBF/SBFMIPeephole.cpp index e88bad1e46c396..17f05b9f1f6923 100644 --- a/llvm/lib/Target/SBF/SBFMIPeephole.cpp +++ b/llvm/lib/Target/SBF/SBFMIPeephole.cpp @@ -20,12 +20,14 @@ // instructions generated due to bad RA on subregister. //===----------------------------------------------------------------------===// +#include "MCTargetDesc/SBFMCTargetDesc.h" #include "SBF.h" #include "SBFInstrInfo.h" #include "SBFTargetMachine.h" #include "llvm/ADT/Statistic.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Support/Debug.h" #include @@ -65,7 +67,9 @@ struct SBFMIPeephole : public MachineFunctionPass { // Main entry point for this pass. bool runOnMachineFunction(MachineFunction &MF) override { - if (skipFunction(MF.getFunction())) + const TargetSubtargetInfo &Target = MF.getSubtarget(); + if (skipFunction(MF.getFunction()) || + Target.getFeatureBits()[SBF::FeatureExplicitSignExt]) return false; initialize(MF); diff --git a/llvm/lib/Target/SBF/SBFSubtarget.cpp b/llvm/lib/Target/SBF/SBFSubtarget.cpp index 3d44332bf2938a..f1676fab44195e 100644 --- a/llvm/lib/Target/SBF/SBFSubtarget.cpp +++ b/llvm/lib/Target/SBF/SBFSubtarget.cpp @@ -47,6 +47,7 @@ void SBFSubtarget::initializeEnvironment(const Triple &TT) { NoLddw = false; CallxRegSrc = false; HasPqrClass = false; + ExplicitSignExt = false; } void SBFSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) { diff --git a/llvm/lib/Target/SBF/SBFSubtarget.h b/llvm/lib/Target/SBF/SBFSubtarget.h index 935fde7ea2ffa0..817e2872a006e0 100644 --- a/llvm/lib/Target/SBF/SBFSubtarget.h +++ b/llvm/lib/Target/SBF/SBFSubtarget.h @@ -80,6 +80,9 @@ class SBFSubtarget : public SBFGenSubtargetInfo { // Whether we have the PQR instruction class bool HasPqrClass; + // Whether to use explict sign extension + bool ExplicitSignExt; + public: // This constructor initializes the data members to match that // of the specified triple. @@ -102,6 +105,7 @@ class SBFSubtarget : public SBFGenSubtargetInfo { bool getNoLddw() const { return NoLddw; } bool getCallXRegSrc() const { return CallxRegSrc; } bool getHasPqrClass() const { return HasPqrClass; } + bool getExplicitSignExt() const { return ExplicitSignExt; } const SBFInstrInfo *getInstrInfo() const override { return &InstrInfo; } const SBFFrameLowering *getFrameLowering() const override { diff --git a/llvm/lib/Target/SBF/SBFTargetFeatures.td b/llvm/lib/Target/SBF/SBFTargetFeatures.td index e4e65004b8a832..d746a1d354d611 100644 --- a/llvm/lib/Target/SBF/SBFTargetFeatures.td +++ b/llvm/lib/Target/SBF/SBFTargetFeatures.td @@ -46,6 +46,9 @@ def FeatureCallxRegSrc : SubtargetFeature<"callx-reg-src", "CallxRegSrc", "true" def FeaturePqrInstr : SubtargetFeature<"pqr-instr", "HasPqrClass", "true", "Enable the PQR instruction class">; +def FeatureExplicitSignExt : SubtargetFeature<"explicit-sext", "ExplicitSignExt", "true", + "Use explicit sign extension">; + class Proc Features> : Processor; @@ -56,4 +59,4 @@ def : Proc<"v3", [ALU32]>; def : Proc<"probe", []>; def : Proc<"sbfv2", [FeatureSolana, FeatureDynamicFrames, FeatureRelocAbs64, FeatureStaticSyscalls, FeatureDisableNeg, FeatureReverseSubImm, FeatureDisableLddw, FeatureCallxRegSrc, - FeaturePqrInstr]>; \ No newline at end of file + FeaturePqrInstr, FeatureExplicitSignExt]>; diff --git a/llvm/test/CodeGen/SBF/explicit-sext.ll b/llvm/test/CodeGen/SBF/explicit-sext.ll new file mode 100644 index 00000000000000..69620bb5a65217 --- /dev/null +++ b/llvm/test/CodeGen/SBF/explicit-sext.ll @@ -0,0 +1,60 @@ +; RUN: llc -march=sbf -mcpu=sbfv2 -mattr=+alu32 < %s | FileCheck %s + +; Function Attrs: mustprogress nofree norecurse nosync nounwind ssp willreturn memory(none) uwtable(sync) +define i64 @zeroext(i32 noundef %a, i32 noundef %b) local_unnamed_addr #0 { +entry: +; CHECK-LABEL: zeroext + %add1 = add i32 %a, %b + %sext1 = zext i32 %add1 to i64 + %res = mul i64 %sext1, 3 + ret i64 %res; + +; Zero extending involves no operation +; CHECK: mov32 w0, w1 +; CHECK: add32 w0, w2 +; CHECK: and32 w0, -1 +; CHECK: mul64 r0, 3 +} + + +; Function Attrs: mustprogress nofree norecurse nosync nounwind ssp willreturn memory(none) uwtable(sync) +define i64 @signext(i32 noundef %a, i32 noundef %b) local_unnamed_addr #0 { +entry: +; CHECK-LABEL: signext + %add1 = add i32 %a, %b + %sext1 = sext i32 %add1 to i64 + %res = mul i64 %sext1, 3 + ret i64 %res + +; Sign extension is a mov32 +; CHECK: add32 w1, w2 +; CHECK: mov32 r0, w1 +; CHECK: mul64 r0, 3 +} + + +; Function Attrs: mustprogress nofree norecurse nosync nounwind ssp willreturn memory(none) uwtable(sync) +define i32 @trunc(i64 noundef %a, i64 noundef %b) local_unnamed_addr #0 { +entry: +; CHECK-LABEL: trunc + %add1 = add i64 %a, %b + %sext1 = trunc i64 %add1 to i32 + %res = mul i32 %sext1, 3 + ret i32 %res + +; Truncation needs the and32 bit mask +; CHECK: mov64 r0, r1 +; CHECK: and32 w2, -1 +; CHECK: and32 w0, -1 +; CHECK: add32 w0, w2 +; CHECK: mul32 w0, 3 +} + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"uwtable", i32 1} +!3 = !{i32 7, !"frame-pointer", i32 1} +!4 = !{!"clang version 16.0.5 (https://github.com/solana-labs/llvm-project.git b33adebdaaa2ac524e019c92b58e77b33cd216fb)"}