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 @@ -69,6 +69,8 @@ let PrintMethod = "printImm64Operand"; } +def gpr_or_imm : Operand; + def i64immSExt32 : PatLeaf<(i64 imm), [{return isInt<32>(N->getSExtValue()); }]>; def i32immSExt32 : PatLeaf<(i32 imm), @@ -476,16 +478,19 @@ : LOAD; let isCodeGenOnly = 1 in { - def CORE_MEM : TYPE_LD_ST; - def CORE_ALU32_MEM : TYPE_LD_ST; + class CORE_LD + : TYPE_LD_ST; + def CORE_LD64 : CORE_LD; + def CORE_LD32 : CORE_LD; + def CORE_ST : TYPE_LD_ST; let Constraints = "$dst = $src" in { def CORE_SHIFT : ALU_RRgetOpcode(); unsigned COREOp; - if (Opcode == BPF::LDB || Opcode == BPF::LDH || Opcode == BPF::LDW || - Opcode == BPF::LDD || Opcode == BPF::STB || Opcode == BPF::STH || - Opcode == BPF::STW || Opcode == BPF::STD || Opcode == BPF::LDWSX || - Opcode == BPF::LDHSX || Opcode == BPF::LDBSX) - COREOp = BPF::CORE_MEM; - else if (Opcode == BPF::LDB32 || Opcode == BPF::LDH32 || - Opcode == BPF::LDW32 || Opcode == BPF::STB32 || - Opcode == BPF::STH32 || Opcode == BPF::STW32) - COREOp = BPF::CORE_ALU32_MEM; + if (isLDX64(Opcode) || isLDSX(Opcode)) + COREOp = BPF::CORE_LD64; + else if (isLDX32(Opcode)) + COREOp = BPF::CORE_LD32; + else if (isSTX64(Opcode) || isSTX32(Opcode)) + COREOp = BPF::CORE_ST; else continue; @@ -138,9 +154,7 @@ // Reject the form: // %1 = ADD_rr %2, %3 // *(type *)(%2 + 0) = %1 - if (Opcode == BPF::STB || Opcode == BPF::STH || Opcode == BPF::STW || - Opcode == BPF::STD || Opcode == BPF::STB32 || Opcode == BPF::STH32 || - Opcode == BPF::STW32) { + if (isSTX64(Opcode) || isSTX32(Opcode)) { const MachineOperand &Opnd = DefInst->getOperand(0); if (Opnd.isReg() && Opnd.getReg() == MO.getReg()) continue; diff --git a/llvm/lib/Target/BPF/BTFDebug.cpp b/llvm/lib/Target/BPF/BTFDebug.cpp --- a/llvm/lib/Target/BPF/BTFDebug.cpp +++ b/llvm/lib/Target/BPF/BTFDebug.cpp @@ -1349,8 +1349,9 @@ // If the insn is "r2 = LD_imm64 @", // The LD_imm64 result will be replaced with a btf type id. processGlobalValue(MI->getOperand(1)); - } else if (MI->getOpcode() == BPF::CORE_MEM || - MI->getOpcode() == BPF::CORE_ALU32_MEM || + } else if (MI->getOpcode() == BPF::CORE_LD64 || + MI->getOpcode() == BPF::CORE_LD32 || + MI->getOpcode() == BPF::CORE_ST || MI->getOpcode() == BPF::CORE_SHIFT) { // relocation insn is a load, store or shift insn. processGlobalValue(MI->getOperand(3)); @@ -1529,8 +1530,9 @@ return true; } } - } else if (MI->getOpcode() == BPF::CORE_MEM || - MI->getOpcode() == BPF::CORE_ALU32_MEM || + } else if (MI->getOpcode() == BPF::CORE_LD64 || + MI->getOpcode() == BPF::CORE_LD32 || + MI->getOpcode() == BPF::CORE_ST || MI->getOpcode() == BPF::CORE_SHIFT) { const MachineOperand &MO = MI->getOperand(3); if (MO.isGlobal()) { diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-simplify-patchable-1.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-simplify-patchable-1.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-simplify-patchable-1.ll @@ -0,0 +1,164 @@ +; RUN: llc -mtriple=bpf -mcpu=v2 < %s | FileCheck -check-prefixes=CHECK,V2 %s +; RUN: llc -mtriple=bpf -mcpu=v4 < %s | FileCheck -check-prefixes=CHECK,V4 %s + +; Verify that BPFMISimplifyPatchable::checkADDrr correctly rewrites +; store instructions. +; +; Generated from the following source code: +; struct t { +; unsigned char ub; +; unsigned short uh; +; unsigned int uw; +; unsigned long ud; +; } __attribute__((preserve_access_index)); +; +; void foo(volatile struct t *t) { +; t->ub = 1; +; t->uh = 2; +; t->uw = 3; +; t->ud = 4; +; } +; +; Using the following command: +; clang -g -O2 -S -emit-llvm --target=bpf t.c -o t.ll + +@"llvm.t:0:0$0:0" = external global i64, !llvm.preserve.access.index !0 #0 +@"llvm.t:0:2$0:1" = external global i64, !llvm.preserve.access.index !0 #0 +@"llvm.t:0:4$0:2" = external global i64, !llvm.preserve.access.index !0 #0 +@"llvm.t:0:8$0:3" = external global i64, !llvm.preserve.access.index !0 #0 + +; Function Attrs: nofree nounwind +define dso_local void @foo(ptr noundef %t, i64 noundef %v) local_unnamed_addr #1 !dbg !18 { +entry: + call void @llvm.dbg.value(metadata ptr %t, metadata !24, metadata !DIExpression()), !dbg !26 + call void @llvm.dbg.value(metadata i64 %v, metadata !25, metadata !DIExpression()), !dbg !26 + %conv = trunc i64 %v to i8, !dbg !27 + %0 = load i64, ptr @"llvm.t:0:0$0:0", align 8 + %1 = getelementptr i8, ptr %t, i64 %0 + %2 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 0, ptr %1) + store volatile i8 %conv, ptr %2, align 8, !dbg !28, !tbaa !29 + %conv1 = trunc i64 %v to i16, !dbg !36 + %3 = load i64, ptr @"llvm.t:0:2$0:1", align 8 + %4 = getelementptr i8, ptr %t, i64 %3 + %5 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 1, ptr %4) + store volatile i16 %conv1, ptr %5, align 2, !dbg !37, !tbaa !38 + %conv2 = trunc i64 %v to i32, !dbg !39 + %6 = load i64, ptr @"llvm.t:0:4$0:2", align 8 + %7 = getelementptr i8, ptr %t, i64 %6 + %8 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 2, ptr %7) + store volatile i32 %conv2, ptr %8, align 4, !dbg !40, !tbaa !41 + %9 = load i64, ptr @"llvm.t:0:8$0:3", align 8 + %10 = getelementptr i8, ptr %t, i64 %9 + %11 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 3, ptr %10) + store volatile i64 %v, ptr %11, align 8, !dbg !42, !tbaa !43 + ret void, !dbg !44 +} + +; CHECK: foo: +; CHECK: prologue_end +; CHECK-NEXT: .Ltmp[[LABEL_UB:.*]]: +; CHECK-NEXT: .Ltmp +; V2-NEXT: *(u8 *)(r1 + 0) = r2 +; V4-NEXT: *(u8 *)(r1 + 0) = w2 +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp[[LABEL_UH:.*]]: +; CHECK-NEXT: .Ltmp +; V2-NEXT: *(u16 *)(r1 + 2) = r2 +; V4-NEXT: *(u16 *)(r1 + 2) = w2 +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp[[LABEL_UW:.*]]: +; CHECK-NEXT: .Ltmp +; V2-NEXT: *(u32 *)(r1 + 4) = r2 +; V4-NEXT: *(u32 *)(r1 + 4) = w2 +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp[[LABEL_UD:.*]]: +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: *(u64 *)(r1 + 8) = r2 + +; CHECK: .section .BTF +; CHECK: .long [[STR_T:.*]] # BTF_KIND_STRUCT(id = [[ID:.*]]) + +; CHECK: .byte 116 # string offset=[[STR_T]] +; CHECK: .ascii "0:0" # string offset=[[STR_UB:.*]] +; CHECK: .ascii "0:1" # string offset=[[STR_UH:.*]] +; CHECK: .ascii "0:2" # string offset=[[STR_UW:.*]] +; CHECK: .ascii "0:3" # string offset=[[STR_UD:.*]] + +; CHECK: # FieldReloc +; CHECK: .long .Ltmp[[LABEL_UB]] +; CHECK-NEXT: .long [[ID]] +; CHECK-NEXT: .long [[STR_UB]] +; CHECK-NEXT: .long 0 +; CHECK: .long .Ltmp[[LABEL_UH]] +; CHECK-NEXT: .long [[ID]] +; CHECK-NEXT: .long [[STR_UH]] +; CHECK-NEXT: .long 0 +; CHECK: .long .Ltmp[[LABEL_UW]] +; CHECK-NEXT: .long [[ID]] +; CHECK-NEXT: .long [[STR_UW]] +; CHECK-NEXT: .long 0 +; CHECK: .long .Ltmp[[LABEL_UD]] +; CHECK-NEXT: .long [[ID]] +; CHECK-NEXT: .long [[STR_UD]] +; CHECK-NEXT: .long 0 + +; Function Attrs: nofree nosync nounwind memory(none) +declare ptr @llvm.bpf.passthrough.p0.p0(i32, ptr) #2 + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { "btf_ama" } +attributes #1 = { nofree nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { nofree nosync nounwind memory(none) } +attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } + +!llvm.dbg.cu = !{!11} +!llvm.module.flags = !{!12, !13, !14, !15, !16} +!llvm.ident = !{!17} + +!0 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !1, line: 1, size: 128, elements: !2) +!1 = !DIFile(filename: "some.file", directory: "/some/dir", checksumkind: CSK_MD5, checksum: "2067f770ab52f9042a61e5bf50a913bd") +!2 = !{!3, !5, !7, !9} +!3 = !DIDerivedType(tag: DW_TAG_member, name: "ub", scope: !0, file: !1, line: 2, baseType: !4, size: 8) +!4 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) +!5 = !DIDerivedType(tag: DW_TAG_member, name: "uh", scope: !0, file: !1, line: 3, baseType: !6, size: 16, offset: 16) +!6 = !DIBasicType(name: "unsigned short", size: 16, encoding: DW_ATE_unsigned) +!7 = !DIDerivedType(tag: DW_TAG_member, name: "uw", scope: !0, file: !1, line: 4, baseType: !8, size: 32, offset: 32) +!8 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!9 = !DIDerivedType(tag: DW_TAG_member, name: "ud", scope: !0, file: !1, line: 5, baseType: !10, size: 64, offset: 64) +!10 = !DIBasicType(name: "unsigned long", size: 64, encoding: DW_ATE_unsigned) +!11 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 18.0.0 (/home/eddy/work/llvm-project/clang 3810f2eb4382d5e2090ce5cd47f45379cb453c35)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!12 = !{i32 7, !"Dwarf Version", i32 5} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{i32 7, !"frame-pointer", i32 2} +!16 = !{i32 7, !"debug-info-assignment-tracking", i1 true} +!17 = !{!"clang version 18.0.0 (/home/eddy/work/llvm-project/clang 3810f2eb4382d5e2090ce5cd47f45379cb453c35)"} +!18 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 13, type: !19, scopeLine: 13, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !11, retainedNodes: !23) +!19 = !DISubroutineType(types: !20) +!20 = !{null, !21, !10} +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) +!22 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !0) +!23 = !{!24, !25} +!24 = !DILocalVariable(name: "t", arg: 1, scope: !18, file: !1, line: 13, type: !21) +!25 = !DILocalVariable(name: "v", arg: 2, scope: !18, file: !1, line: 13, type: !10) +!26 = !DILocation(line: 0, scope: !18) +!27 = !DILocation(line: 14, column: 11, scope: !18) +!28 = !DILocation(line: 14, column: 9, scope: !18) +!29 = !{!30, !31, i64 0} +!30 = !{!"t", !31, i64 0, !33, i64 2, !34, i64 4, !35, i64 8} +!31 = !{!"omnipotent char", !32, i64 0} +!32 = !{!"Simple C/C++ TBAA"} +!33 = !{!"short", !31, i64 0} +!34 = !{!"int", !31, i64 0} +!35 = !{!"long", !31, i64 0} +!36 = !DILocation(line: 15, column: 11, scope: !18) +!37 = !DILocation(line: 15, column: 9, scope: !18) +!38 = !{!30, !33, i64 2} +!39 = !DILocation(line: 16, column: 11, scope: !18) +!40 = !DILocation(line: 16, column: 9, scope: !18) +!41 = !{!30, !34, i64 4} +!42 = !DILocation(line: 17, column: 9, scope: !18) +!43 = !{!30, !35, i64 8} +!44 = !DILocation(line: 18, column: 1, scope: !18) diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-simplify-patchable-2.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-simplify-patchable-2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-simplify-patchable-2.ll @@ -0,0 +1,196 @@ +; RUN: llc -mtriple=bpf -mcpu=v2 < %s | FileCheck -check-prefixes=CHECK,V2 %s +; RUN: llc -mtriple=bpf -mcpu=v4 < %s | FileCheck -check-prefixes=CHECK,V4 %s + +; Verify that BPFMISimplifyPatchable::checkADDrr correctly rewrites +; load instructions. +; +; Generated from the following source code: +; struct t { +; unsigned char ub; +; unsigned short uh; +; unsigned int uw; +; unsigned long ud; +; } __attribute__((preserve_access_index)); +; +; extern void cu(unsigned long); +; +; void bar(volatile struct t *t) { +; cu(t->ub); +; cu(t->uh); +; cu(t->uw); +; cu(t->ud); +; } +; +; Using the following command: +; clang -g -O2 -S -emit-llvm --target=bpf t.c -o t.ll + +@"llvm.t:0:0$0:0" = external global i64, !llvm.preserve.access.index !0 #0 +@"llvm.t:0:2$0:1" = external global i64, !llvm.preserve.access.index !0 #0 +@"llvm.t:0:4$0:2" = external global i64, !llvm.preserve.access.index !0 #0 +@"llvm.t:0:8$0:3" = external global i64, !llvm.preserve.access.index !0 #0 + +; Function Attrs: nounwind +define dso_local void @bar(ptr noundef %t) local_unnamed_addr #1 !dbg !18 { +entry: + call void @llvm.dbg.value(metadata ptr %t, metadata !24, metadata !DIExpression()), !dbg !25 + %0 = load i64, ptr @"llvm.t:0:0$0:0", align 8 + %1 = getelementptr i8, ptr %t, i64 %0 + %2 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 0, ptr %1) + %3 = load volatile i8, ptr %2, align 8, !dbg !26, !tbaa !27 + %conv = zext i8 %3 to i64, !dbg !34 + tail call void @cu(i64 noundef %conv) #5, !dbg !35 + %4 = load i64, ptr @"llvm.t:0:2$0:1", align 8 + %5 = getelementptr i8, ptr %t, i64 %4 + %6 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 1, ptr %5) + %7 = load volatile i16, ptr %6, align 2, !dbg !36, !tbaa !37 + %conv1 = zext i16 %7 to i64, !dbg !38 + tail call void @cu(i64 noundef %conv1) #5, !dbg !39 + %8 = load i64, ptr @"llvm.t:0:4$0:2", align 8 + %9 = getelementptr i8, ptr %t, i64 %8 + %10 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 2, ptr %9) + %11 = load volatile i32, ptr %10, align 4, !dbg !40, !tbaa !41 + %conv2 = zext i32 %11 to i64, !dbg !42 + tail call void @cu(i64 noundef %conv2) #5, !dbg !43 + %12 = load i64, ptr @"llvm.t:0:8$0:3", align 8 + %13 = getelementptr i8, ptr %t, i64 %12 + %14 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 3, ptr %13) + %15 = load volatile i64, ptr %14, align 8, !dbg !44, !tbaa !45 + tail call void @cu(i64 noundef %15) #5, !dbg !46 + ret void, !dbg !47 +} + +; CHECK: bar: +; CHECK: prologue_end +; CHECK-NEXT: .Ltmp[[LABEL_UB:.*]]: +; CHECK-NEXT: .Ltmp +; V2-NEXT: r1 = *(u8 *)(r6 + 0) +; V4-NEXT: w1 = *(u8 *)(r6 + 0) +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: call cu +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp[[LABEL_UH:.*]]: +; CHECK-NEXT: .Ltmp +; V2-NEXT: r1 = *(u16 *)(r6 + 2) +; V4-NEXT: w1 = *(u16 *)(r6 + 2) +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: call cu +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp[[LABEL_UW:.*]]: +; CHECK-NEXT: .Ltmp +; V2-NEXT: r1 = *(u32 *)(r6 + 4) +; V4-NEXT: w1 = *(u32 *)(r6 + 4) +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: call cu +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp[[LABEL_UD:.*]]: +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: r1 = *(u64 *)(r6 + 8) +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: call cu + +; CHECK: .section .BTF +; CHECK: .long [[STR_T:.*]] # BTF_KIND_STRUCT(id = [[ID:.*]]) + +; CHECK: .byte 116 # string offset=[[STR_T]] +; CHECK: .ascii "0:0" # string offset=[[STR_UB:.*]] +; CHECK: .ascii "0:1" # string offset=[[STR_UH:.*]] +; CHECK: .ascii "0:2" # string offset=[[STR_UW:.*]] +; CHECK: .ascii "0:3" # string offset=[[STR_UD:.*]] + +; CHECK: # FieldReloc +; CHECK: .long .Ltmp[[LABEL_UB]] +; CHECK-NEXT: .long [[ID]] +; CHECK-NEXT: .long [[STR_UB]] +; CHECK-NEXT: .long 0 +; CHECK: .long .Ltmp[[LABEL_UH]] +; CHECK-NEXT: .long [[ID]] +; CHECK-NEXT: .long [[STR_UH]] +; CHECK-NEXT: .long 0 +; CHECK: .long .Ltmp[[LABEL_UW]] +; CHECK-NEXT: .long [[ID]] +; CHECK-NEXT: .long [[STR_UW]] +; CHECK-NEXT: .long 0 +; CHECK: .long .Ltmp[[LABEL_UD]] +; CHECK-NEXT: .long [[ID]] +; CHECK-NEXT: .long [[STR_UD]] +; CHECK-NEXT: .long 0 + +declare !dbg !48 dso_local void @cu(i64 noundef) local_unnamed_addr #2 + +; Function Attrs: nofree nosync nounwind memory(none) +declare ptr @llvm.bpf.passthrough.p0.p0(i32, ptr) #3 + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.value(metadata, metadata, metadata) #4 + +attributes #0 = { "btf_ama" } +attributes #1 = { nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #3 = { nofree nosync nounwind memory(none) } +attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } +attributes #5 = { nounwind } + +!llvm.dbg.cu = !{!11} +!llvm.module.flags = !{!12, !13, !14, !15, !16} +!llvm.ident = !{!17} + +!0 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !1, line: 1, size: 128, elements: !2) +!1 = !DIFile(filename: "some.file", directory: "/some/dir", checksumkind: CSK_MD5, checksum: "d08c6eeba11118106c69a68932003da2") +!2 = !{!3, !5, !7, !9} +!3 = !DIDerivedType(tag: DW_TAG_member, name: "ub", scope: !0, file: !1, line: 2, baseType: !4, size: 8) +!4 = !DIBasicType(name: "unsigned char", size: 8, encoding: DW_ATE_unsigned_char) +!5 = !DIDerivedType(tag: DW_TAG_member, name: "uh", scope: !0, file: !1, line: 3, baseType: !6, size: 16, offset: 16) +!6 = !DIBasicType(name: "unsigned short", size: 16, encoding: DW_ATE_unsigned) +!7 = !DIDerivedType(tag: DW_TAG_member, name: "uw", scope: !0, file: !1, line: 4, baseType: !8, size: 32, offset: 32) +!8 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!9 = !DIDerivedType(tag: DW_TAG_member, name: "ud", scope: !0, file: !1, line: 5, baseType: !10, size: 64, offset: 64) +!10 = !DIBasicType(name: "unsigned long", size: 64, encoding: DW_ATE_unsigned) +!11 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 18.0.0 (/home/eddy/work/llvm-project/clang 3810f2eb4382d5e2090ce5cd47f45379cb453c35)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!12 = !{i32 7, !"Dwarf Version", i32 5} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{i32 7, !"frame-pointer", i32 2} +!16 = !{i32 7, !"debug-info-assignment-tracking", i1 true} +!17 = !{!"clang version 18.0.0 (/home/eddy/work/llvm-project/clang 3810f2eb4382d5e2090ce5cd47f45379cb453c35)"} +!18 = distinct !DISubprogram(name: "bar", scope: !1, file: !1, line: 20, type: !19, scopeLine: 20, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !11, retainedNodes: !23) +!19 = !DISubroutineType(types: !20) +!20 = !{null, !21} +!21 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !22, size: 64) +!22 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !0) +!23 = !{!24} +!24 = !DILocalVariable(name: "t", arg: 1, scope: !18, file: !1, line: 20, type: !21) +!25 = !DILocation(line: 0, scope: !18) +!26 = !DILocation(line: 21, column: 9, scope: !18) +!27 = !{!28, !29, i64 0} +!28 = !{!"t", !29, i64 0, !31, i64 2, !32, i64 4, !33, i64 8} +!29 = !{!"omnipotent char", !30, i64 0} +!30 = !{!"Simple C/C++ TBAA"} +!31 = !{!"short", !29, i64 0} +!32 = !{!"int", !29, i64 0} +!33 = !{!"long", !29, i64 0} +!34 = !DILocation(line: 21, column: 6, scope: !18) +!35 = !DILocation(line: 21, column: 3, scope: !18) +!36 = !DILocation(line: 22, column: 9, scope: !18) +!37 = !{!28, !31, i64 2} +!38 = !DILocation(line: 22, column: 6, scope: !18) +!39 = !DILocation(line: 22, column: 3, scope: !18) +!40 = !DILocation(line: 23, column: 9, scope: !18) +!41 = !{!28, !32, i64 4} +!42 = !DILocation(line: 23, column: 6, scope: !18) +!43 = !DILocation(line: 23, column: 3, scope: !18) +!44 = !DILocation(line: 24, column: 9, scope: !18) +!45 = !{!28, !33, i64 8} +!46 = !DILocation(line: 24, column: 3, scope: !18) +!47 = !DILocation(line: 25, column: 1, scope: !18) +!48 = !DISubprogram(name: "cu", scope: !1, file: !1, line: 10, type: !49, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !51) +!49 = !DISubroutineType(types: !50) +!50 = !{null, !10} +!51 = !{!52} +!52 = !DILocalVariable(arg: 1, scope: !48, file: !1, line: 10, type: !10) diff --git a/llvm/test/CodeGen/BPF/CORE/offset-reloc-simplify-patchable-3.ll b/llvm/test/CodeGen/BPF/CORE/offset-reloc-simplify-patchable-3.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/CORE/offset-reloc-simplify-patchable-3.ll @@ -0,0 +1,166 @@ +; RUN: llc -mtriple=bpf -mcpu=v4 < %s | FileCheck -check-prefixes=CHECK %s + +; Verify that BPFMISimplifyPatchable::checkADDrr correctly rewrites +; load instructions with sign extension. +; +; Generated from the following source code: +; struct t { +; signed char sb; +; signed short sh; +; signed int sw; +; } __attribute__((preserve_access_index)); +; +; extern void cs(signed long); +; +; void buz(volatile struct t *t) { +; cs(t->sb); +; cs(t->sh); +; cs(t->sw); +; } +; +; Using the following command: +; clang -g -O2 -S -emit-llvm --target=bpf t.c -o t.ll + +@"llvm.t:0:0$0:0" = external global i64, !llvm.preserve.access.index !0 #0 +@"llvm.t:0:2$0:1" = external global i64, !llvm.preserve.access.index !0 #0 +@"llvm.t:0:4$0:2" = external global i64, !llvm.preserve.access.index !0 #0 + +; Function Attrs: nounwind +define dso_local void @buz(ptr noundef %t) local_unnamed_addr #1 !dbg !16 { +entry: + call void @llvm.dbg.value(metadata ptr %t, metadata !22, metadata !DIExpression()), !dbg !23 + %0 = load i64, ptr @"llvm.t:0:0$0:0", align 8 + %1 = getelementptr i8, ptr %t, i64 %0 + %2 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 0, ptr %1) + %3 = load volatile i8, ptr %2, align 4, !dbg !24, !tbaa !25 + %conv = sext i8 %3 to i64, !dbg !31 + tail call void @cs(i64 noundef %conv) #5, !dbg !32 + %4 = load i64, ptr @"llvm.t:0:2$0:1", align 8 + %5 = getelementptr i8, ptr %t, i64 %4 + %6 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 1, ptr %5) + %7 = load volatile i16, ptr %6, align 2, !dbg !33, !tbaa !34 + %conv1 = sext i16 %7 to i64, !dbg !35 + tail call void @cs(i64 noundef %conv1) #5, !dbg !36 + %8 = load i64, ptr @"llvm.t:0:4$0:2", align 8 + %9 = getelementptr i8, ptr %t, i64 %8 + %10 = tail call ptr @llvm.bpf.passthrough.p0.p0(i32 2, ptr %9) + %11 = load volatile i32, ptr %10, align 4, !dbg !37, !tbaa !38 + %conv2 = sext i32 %11 to i64, !dbg !39 + tail call void @cs(i64 noundef %conv2) #5, !dbg !40 + ret void, !dbg !41 +} + +; CHECK: buz: +; CHECK: prologue_end +; CHECK-NEXT: .Ltmp[[LABEL_SB:.*]]: +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: r1 = *(s8 *)(r6 + 0) +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: call cs +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp[[LABEL_SH:.*]]: +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: r1 = *(s16 *)(r6 + 2) +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: call cs +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp[[LABEL_SW:.*]]: +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: r1 = *(s32 *)(r6 + 4) +; CHECK-NEXT: .loc +; CHECK-NEXT: .Ltmp +; CHECK-NEXT: call cs + +; CHECK: .section .BTF +; CHECK: .long [[T:.*]] # BTF_KIND_STRUCT(id = [[ID:.*]]) + +; CHECK: .byte 116 # string offset=[[T]] +; CHECK: .ascii "0:0" # string offset=[[STR_SB:.*]] +; CHECK: .ascii "0:1" # string offset=[[STR_SH:.*]] +; CHECK: .ascii "0:2" # string offset=[[STR_SW:.*]] + +; CHECK: # FieldReloc +; CHECK: .long .Ltmp[[LABEL_SB]] +; CHECK-NEXT: .long [[ID]] +; CHECK-NEXT: .long [[STR_SB]] +; CHECK-NEXT: .long 0 +; CHECK: .long .Ltmp[[LABEL_SH]] +; CHECK-NEXT: .long [[ID]] +; CHECK-NEXT: .long [[STR_SH]] +; CHECK-NEXT: .long 0 +; CHECK: .long .Ltmp[[LABEL_SW]] +; CHECK-NEXT: .long [[ID]] +; CHECK-NEXT: .long [[STR_SW]] +; CHECK-NEXT: .long 0 + +declare !dbg !42 dso_local void @cs(i64 noundef) local_unnamed_addr #2 + +; Function Attrs: nofree nosync nounwind memory(none) +declare ptr @llvm.bpf.passthrough.p0.p0(i32, ptr) #3 + +; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare void @llvm.dbg.value(metadata, metadata, metadata) #4 + +attributes #0 = { "btf_ama" } +attributes #1 = { nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #2 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #3 = { nofree nosync nounwind memory(none) } +attributes #4 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } +attributes #5 = { nounwind } + +!llvm.dbg.cu = !{!9} +!llvm.module.flags = !{!10, !11, !12, !13, !14} +!llvm.ident = !{!15} + +!0 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "t", file: !1, line: 1, size: 64, elements: !2) +!1 = !DIFile(filename: "some.file", directory: "/some/dir", checksumkind: CSK_MD5, checksum: "2316ba0d3e8def5d297ad400e78b1782") +!2 = !{!3, !5, !7} +!3 = !DIDerivedType(tag: DW_TAG_member, name: "sb", scope: !0, file: !1, line: 6, baseType: !4, size: 8) +!4 = !DIBasicType(name: "signed char", size: 8, encoding: DW_ATE_signed_char) +!5 = !DIDerivedType(tag: DW_TAG_member, name: "sh", scope: !0, file: !1, line: 7, baseType: !6, size: 16, offset: 16) +!6 = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed) +!7 = !DIDerivedType(tag: DW_TAG_member, name: "sw", scope: !0, file: !1, line: 8, baseType: !8, size: 32, offset: 32) +!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!9 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 18.0.0 (/home/eddy/work/llvm-project/clang 3810f2eb4382d5e2090ce5cd47f45379cb453c35)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None) +!10 = !{i32 7, !"Dwarf Version", i32 5} +!11 = !{i32 2, !"Debug Info Version", i32 3} +!12 = !{i32 1, !"wchar_size", i32 4} +!13 = !{i32 7, !"frame-pointer", i32 2} +!14 = !{i32 7, !"debug-info-assignment-tracking", i1 true} +!15 = !{!"clang version 18.0.0 (/home/eddy/work/llvm-project/clang 3810f2eb4382d5e2090ce5cd47f45379cb453c35)"} +!16 = distinct !DISubprogram(name: "buz", scope: !1, file: !1, line: 27, type: !17, scopeLine: 27, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !9, retainedNodes: !21) +!17 = !DISubroutineType(types: !18) +!18 = !{null, !19} +!19 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !20, size: 64) +!20 = !DIDerivedType(tag: DW_TAG_volatile_type, baseType: !0) +!21 = !{!22} +!22 = !DILocalVariable(name: "t", arg: 1, scope: !16, file: !1, line: 27, type: !19) +!23 = !DILocation(line: 0, scope: !16) +!24 = !DILocation(line: 28, column: 9, scope: !16) +!25 = !{!26, !27, i64 0} +!26 = !{!"t", !27, i64 0, !29, i64 2, !30, i64 4} +!27 = !{!"omnipotent char", !28, i64 0} +!28 = !{!"Simple C/C++ TBAA"} +!29 = !{!"short", !27, i64 0} +!30 = !{!"int", !27, i64 0} +!31 = !DILocation(line: 28, column: 6, scope: !16) +!32 = !DILocation(line: 28, column: 3, scope: !16) +!33 = !DILocation(line: 29, column: 9, scope: !16) +!34 = !{!26, !29, i64 2} +!35 = !DILocation(line: 29, column: 6, scope: !16) +!36 = !DILocation(line: 29, column: 3, scope: !16) +!37 = !DILocation(line: 30, column: 9, scope: !16) +!38 = !{!26, !30, i64 4} +!39 = !DILocation(line: 30, column: 6, scope: !16) +!40 = !DILocation(line: 30, column: 3, scope: !16) +!41 = !DILocation(line: 31, column: 1, scope: !16) +!42 = !DISubprogram(name: "cs", scope: !1, file: !1, line: 11, type: !43, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !46) +!43 = !DISubroutineType(types: !44) +!44 = !{null, !45} +!45 = !DIBasicType(name: "long", size: 64, encoding: DW_ATE_signed) +!46 = !{!47} +!47 = !DILocalVariable(arg: 1, scope: !42, file: !1, line: 11, type: !45)