65816-llvm-mos/src/llvm/test/CodeGen/W65816/i32-half-offset-fold.ll
2026-10-06 17:01:51 -05:00

82 lines
2.6 KiB
LLVM

; Pin: both halves of an i32 load or store through a far pointer address
; the pointer's base with the field offset in Y. The high half of an
; i32 load at `p + K` is a load at `(p + K) + 2`; peeling only the outer
; +2 left it addressed through the computed `p + K` (an i32 add and a
; staging of its result into $E0 / $E2 per access). The i32 store path
; did not peel at all: its high half always took `p + 2` through an i32
; add. A `+ K` whose constant was already split into halves by
; LowerI32Constant now peels too. CoreMark's linked-list code
; (list->info, list->next) went -7% total time with this.
;
; RUN: llc -mtriple=w65816 -O2 < %s | FileCheck %s
target datalayout = "e-m:e-p:32:16-i16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16"
; The pointer field at offset 4: low half at Y=4, high half at Y=6, no
; carry chain (the `adc #0x0` of an i32 address add).
define ptr @getInfo(ptr %n) {
; CHECK-LABEL: getInfo:
; CHECK-NOT: adc #0x0
; CHECK-DAG: ldy #0x4
; CHECK-DAG: ldy #0x6
; CHECK-NOT: adc #0x0
; CHECK: rtl
%f = getelementptr inbounds i8, ptr %n, i32 4
%v = load ptr, ptr %f, align 2
ret ptr %v
}
; An i32 store at offset 8: Y=8 then Y=10 off the incoming pointer.
define void @setCnt(ptr %n, i32 %v) {
; CHECK-LABEL: setCnt:
; CHECK-NOT: adc #0x0
; CHECK: ldy #0x8
; CHECK-NEXT: sta [0x{{[0-9a-f]+}}], y
; CHECK-NOT: adc #0x0
; CHECK: ldy #0xa
; CHECK-NEXT: sta [0x{{[0-9a-f]+}}], y
; CHECK-NOT: adc #0x0
; CHECK: rtl
%f = getelementptr inbounds i8, ptr %n, i32 8
store i32 %v, ptr %f, align 2
ret void
}
; An i32 store at offset 0: the high half is Y=2 off the same base.
define void @setFirst(ptr %n, i32 %v) {
; CHECK-LABEL: setFirst:
; CHECK-NOT: adc #0x0
; CHECK: ldy #0x2
; CHECK-NOT: adc #0x0
; CHECK: rtl
store i32 %v, ptr %n, align 2
ret void
}
; A read-modify-write of an i32 element (CoreMark's transition_count[i]++):
; four [p],Y accesses at Y=8 / Y=10, the only add the increment's.
define void @bump(ptr %tc) {
; CHECK-LABEL: bump:
; CHECK-NOT: adc #0x2
; CHECK-NOT: adc #0x8
; CHECK-DAG: ldy #0x8
; CHECK-DAG: ldy #0xa
; CHECK-NOT: adc #0x2
; CHECK-NOT: adc #0x8
; CHECK: rtl
%p = getelementptr inbounds i8, ptr %tc, i32 8
%v = load i32, ptr %p, align 2
%w = add i32 %v, 1
store i32 %w, ptr %p, align 2
ret void
}
; Offsets that no longer fit Y fall back to the i32 add.
define void @setFar(ptr %n, i32 %v) {
; CHECK-LABEL: setFar:
; CHECK: adc #0xfffe
; CHECK: rtl
%f = getelementptr inbounds i8, ptr %n, i32 65534
store i32 %v, ptr %f, align 2
ret void
}