82 lines
2.6 KiB
LLVM
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
|
|
}
|