diff --git a/llvm/lib/Target/BPF/BPFISelLowering.cpp b/llvm/lib/Target/BPF/BPFISelLowering.cpp --- a/llvm/lib/Target/BPF/BPFISelLowering.cpp +++ b/llvm/lib/Target/BPF/BPFISelLowering.cpp @@ -140,10 +140,6 @@ setLoadExtAction(ISD::EXTLOAD, VT, MVT::i1, Promote); setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i1, Promote); setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote); - - setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i8, Expand); - setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i16, Expand); - setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i32, Expand); } setBooleanContents(ZeroOrOneBooleanContent); diff --git a/llvm/lib/Target/BPF/BPFInstrFormats.td b/llvm/lib/Target/BPF/BPFInstrFormats.td --- a/llvm/lib/Target/BPF/BPFInstrFormats.td +++ b/llvm/lib/Target/BPF/BPFInstrFormats.td @@ -90,6 +90,7 @@ def BPF_ABS : BPFModeModifer<0x1>; def BPF_IND : BPFModeModifer<0x2>; def BPF_MEM : BPFModeModifer<0x3>; +def BPF_MEM_SEXT : BPFModeModifer<0x4>; def BPF_ATOMIC : BPFModeModifer<0x6>; class BPFAtomicFlag val> { diff --git a/llvm/lib/Target/BPF/BPFInstrInfo.td b/llvm/lib/Target/BPF/BPFInstrInfo.td --- a/llvm/lib/Target/BPF/BPFInstrInfo.td +++ b/llvm/lib/Target/BPF/BPFInstrInfo.td @@ -421,8 +421,8 @@ def STD : STOREi64; // LOAD instructions -class LOAD Pattern> - : TYPE_LD_ST Pattern> + : TYPE_LD_ST - : LOAD; +class LOADi64 + : LOAD; let isCodeGenOnly = 1 in { def CORE_MEM : TYPE_LD_ST; - def LDH : LOADi64; - def LDB : LOADi64; + def LDW : LOADi64; + def LDH : LOADi64; + def LDB : LOADi64; + + def LDWS : LOADi64; + def LDHS : LOADi64; + def LDBS : LOADi64; } -def LDD : LOADi64; +def LDD : LOADi64; class BRANCH Pattern> : TYPE_ALU_JMP; } -class LOAD32 Pattern> - : TYPE_LD_ST Pattern> + : TYPE_LD_ST - : LOAD32; +class LOADi32 + : LOAD32; let Predicates = [BPFHasALU32], DecoderNamespace = "BPFALU32" in { - def LDW32 : LOADi32; - def LDH32 : LOADi32; - def LDB32 : LOADi32; + def LDW32 : LOADi32; + def LDH32 : LOADi32; + def LDB32 : LOADi32; + + def LDH32S : LOADi32; + def LDB32S : LOADi32; } let Predicates = [BPFHasALU32] in { @@ -973,6 +980,8 @@ (STW32 (EXTRACT_SUBREG GPR:$src, sub_32), ADDRri:$dst)>; def : Pat<(i32 (extloadi8 ADDRri:$src)), (i32 (LDB32 ADDRri:$src))>; def : Pat<(i32 (extloadi16 ADDRri:$src)), (i32 (LDH32 ADDRri:$src))>; + def : Pat<(i32 (sextloadi8 ADDRri:$src)), (i32 (LDB32S ADDRri:$src))>; + def : Pat<(i32 (sextloadi16 ADDRri:$src)), (i32 (LDH32S ADDRri:$src))>; def : Pat<(i64 (zextloadi8 ADDRri:$src)), (SUBREG_TO_REG (i64 0), (LDB32 ADDRri:$src), sub_32)>; def : Pat<(i64 (zextloadi16 ADDRri:$src)), @@ -985,6 +994,9 @@ (SUBREG_TO_REG (i64 0), (LDH32 ADDRri:$src), sub_32)>; def : Pat<(i64 (extloadi32 ADDRri:$src)), (SUBREG_TO_REG (i64 0), (LDW32 ADDRri:$src), sub_32)>; + def : Pat<(i64 (sextloadi8 ADDRri:$src)), (i64 (LDBS ADDRri:$src))>; + def : Pat<(i64 (sextloadi16 ADDRri:$src)), (i64 (LDHS ADDRri:$src))>; + def : Pat<(i64 (sextloadi32 ADDRri:$src)), (i64 (LDWS ADDRri:$src))>; } let usesCustomInserter = 1, isCodeGenOnly = 1 in { diff --git a/llvm/lib/Target/BPF/Disassembler/BPFDisassembler.cpp b/llvm/lib/Target/BPF/Disassembler/BPFDisassembler.cpp --- a/llvm/lib/Target/BPF/Disassembler/BPFDisassembler.cpp +++ b/llvm/lib/Target/BPF/Disassembler/BPFDisassembler.cpp @@ -57,6 +57,7 @@ BPF_ABS = 0x1, BPF_IND = 0x2, BPF_MEM = 0x3, + BPF_MEM_SEXT = 0x4, BPF_LEN = 0x4, BPF_MSH = 0x5, BPF_ATOMIC = 0x6 diff --git a/llvm/test/CodeGen/BPF/sext.ll b/llvm/test/CodeGen/BPF/sext.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/sext.ll @@ -0,0 +1,112 @@ +; RUN: llc -O2 -march=bpfel -mcpu=v1 < %s | FileCheck -check-prefixes=CHECK -check-prefixes=CHECKV1 %s +; RUN: llc -O2 -march=bpfel -mcpu=v3 < %s | FileCheck -check-prefixes=CHECK -check-prefixes=CHECKV3 %s +; Source: +; int f1(char *p) { +; return *p; +; } +; int f2(short *p) { +; return *p; +; } +; int f3(int *p) { +; return *p; +; } +; long f4(char *p) { +; return *p; +; } +; long f5(short *p) { +; return *p; +; } +; long f6(int *p) { +; return *p; +; } +; long f7(long *p) { +; return *p; +; } +; Compilation flags: +; clang -target bpf -O2 -S -emit-llvm -Xclang -disable-llvm-passes t.c + +; Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn +define dso_local i32 @f1(ptr nocapture noundef readonly %p) local_unnamed_addr #0 { +entry: + %0 = load i8, ptr %p, align 1, !tbaa !3 + %conv = sext i8 %0 to i32 +; CHECKV1: r0 = *(s8 *)(r1 + 0) +; CHECKV3: w0 = *(s8 *)(r1 + 0) + ret i32 %conv +} + +; Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn +define dso_local i32 @f2(ptr nocapture noundef readonly %p) local_unnamed_addr #0 { +entry: + %0 = load i16, ptr %p, align 2, !tbaa !6 + %conv = sext i16 %0 to i32 +; CHECKV1: r0 = *(s16 *)(r1 + 0) +; CHECKV3: w0 = *(s16 *)(r1 + 0) + ret i32 %conv +} + +; Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn +define dso_local i32 @f3(ptr nocapture noundef readonly %p) local_unnamed_addr #0 { +entry: + %0 = load i32, ptr %p, align 4, !tbaa !8 +; CHECKV1: r0 = *(u32 *)(r1 + 0) +; CHECKV3: w0 = *(u32 *)(r1 + 0) + ret i32 %0 +} + +; Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn +define dso_local i64 @f4(ptr nocapture noundef readonly %p) local_unnamed_addr #0 { +entry: + %0 = load i8, ptr %p, align 1, !tbaa !3 + %conv = sext i8 %0 to i64 + ret i64 %conv +; CHECK: r0 = *(s8 *)(r1 + 0) +; CHECK-NEXT: exit +} + +; Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn +define dso_local i64 @f5(ptr nocapture noundef readonly %p) local_unnamed_addr #0 { +entry: + %0 = load i16, ptr %p, align 2, !tbaa !6 + %conv = sext i16 %0 to i64 + ret i64 %conv +; CHECK: r0 = *(s16 *)(r1 + 0) +; CHECK-NEXT: exit +} + +; Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn +define dso_local i64 @f6(ptr nocapture noundef readonly %p) local_unnamed_addr #0 { +entry: + %0 = load i32, ptr %p, align 4, !tbaa !8 + %conv = sext i32 %0 to i64 + ret i64 %conv +; CHECK: r0 = *(s32 *)(r1 + 0) +; CHECK-NEXT: exit +} + +; Function Attrs: argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn +define dso_local i64 @f7(ptr nocapture noundef readonly %p) local_unnamed_addr #0 { +entry: + %0 = load i64, ptr %p, align 8, !tbaa !10 + ret i64 %0 +; CHECK: r0 = *(u64 *)(r1 + 0) +; CHECK-NEXT: exit +} + +attributes #0 = { argmemonly mustprogress nofree norecurse nosync nounwind readonly willreturn "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 7, !"frame-pointer", i32 2} +!2 = !{!"clang version 16.0.0 (https://github.com/llvm/llvm-project.git 68665544c7d59735e9c0bb32b08829c006c7c594)"} +!3 = !{!4, !4, i64 0} +!4 = !{!"omnipotent char", !5, i64 0} +!5 = !{!"Simple C/C++ TBAA"} +!6 = !{!7, !7, i64 0} +!7 = !{!"short", !4, i64 0} +!8 = !{!9, !9, i64 0} +!9 = !{!"int", !4, i64 0} +!10 = !{!11, !11, i64 0} +!11 = !{!"long", !4, i64 0}