| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6 | |
| ; RUN: llc -verify-machineinstrs < %s -mtriple=powerpc-unknown-linux-gnu \ | |
| ; RUN: -mattr=+spe -O2 | FileCheck %s | |
| ; Regression test for a bug where evldd and evstdd used an offset that does not actually fit | |
| ; in the instruction encoding. They have a 5-bit displacement that gets multiplied by 8, so | |
| ; the maximum offset they can encode is `31 * 8 = 248`. For anything higher, these instructions | |
| ; cannot be used. | |
| declare void @use(ptr) | |
| define void @store_in_range(double %x) { | |
| ; CHECK-LABEL: store_in_range: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: mflr 0 | |
| ; CHECK-NEXT: stwu 1, -256(1) | |
| ; CHECK-NEXT: stw 0, 260(1) | |
| ; CHECK-NEXT: .cfi_def_cfa_offset 256 | |
| ; CHECK-NEXT: .cfi_offset lr, 4 | |
| ; CHECK-NEXT: evmergelo 3, 3, 4 | |
| ; CHECK-NEXT: evstdd 3, 248(1) | |
| ; CHECK-NEXT: addi 3, 1, 8 | |
| ; CHECK-NEXT: bl use | |
| ; CHECK-NEXT: lwz 0, 260(1) | |
| ; CHECK-NEXT: addi 1, 1, 256 | |
| ; CHECK-NEXT: mtlr 0 | |
| ; CHECK-NEXT: blr | |
| %d = alloca double, align 8 | |
| %large = alloca [240 x i8], align 8 | |
| store double %x, ptr %d, align 8 | |
| call void @use(ptr %large) | |
| ret void | |
| } | |
| define void @store_unaligned_in_range(double %x) { | |
| ; CHECK-LABEL: store_unaligned_in_range: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: mflr 0 | |
| ; CHECK-NEXT: stwu 1, -32(1) | |
| ; CHECK-NEXT: stw 0, 36(1) | |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 | |
| ; CHECK-NEXT: .cfi_offset lr, 4 | |
| ; CHECK-NEXT: evmergelo 3, 3, 4 | |
| ; CHECK-NEXT: evstdd 3, 8(1) | |
| ; CHECK-NEXT: lwz 3, 8(1) | |
| ; CHECK-NEXT: stw 3, 17(1) | |
| ; CHECK-NEXT: lwz 3, 12(1) | |
| ; CHECK-NEXT: stw 3, 21(1) | |
| ; CHECK-NEXT: addi 3, 1, 16 | |
| ; CHECK-NEXT: bl use | |
| ; CHECK-NEXT: lwz 0, 36(1) | |
| ; CHECK-NEXT: addi 1, 1, 32 | |
| ; CHECK-NEXT: mtlr 0 | |
| ; CHECK-NEXT: blr | |
| %buf = alloca [16 x i8], align 8 | |
| %p = getelementptr i8, ptr %buf, i32 1 | |
| store double %x, ptr %p, align 1 | |
| call void @use(ptr %buf) | |
| ret void | |
| } | |
| define void @store_unaligned_offset_248(double %x) { | |
| ; CHECK-LABEL: store_unaligned_offset_248: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: mflr 0 | |
| ; CHECK-NEXT: stwu 1, -288(1) | |
| ; CHECK-NEXT: stw 0, 292(1) | |
| ; CHECK-NEXT: .cfi_def_cfa_offset 288 | |
| ; CHECK-NEXT: .cfi_offset lr, 4 | |
| ; CHECK-NEXT: evmergelo 3, 3, 4 | |
| ; CHECK-NEXT: evstdd 3, 16(1) | |
| ; CHECK-NEXT: lwz 3, 16(1) | |
| ; CHECK-NEXT: stw 3, 273(1) | |
| ; CHECK-NEXT: lwz 3, 20(1) | |
| ; CHECK-NEXT: stw 3, 277(1) | |
| ; CHECK-NEXT: addi 3, 1, 24 | |
| ; CHECK-NEXT: bl use | |
| ; CHECK-NEXT: lwz 0, 292(1) | |
| ; CHECK-NEXT: addi 1, 1, 288 | |
| ; CHECK-NEXT: mtlr 0 | |
| ; CHECK-NEXT: blr | |
| %buf = alloca [264 x i8], align 8 | |
| %p = getelementptr i8, ptr %buf, i32 249 | |
| store double %x, ptr %p, align 1 | |
| call void @use(ptr %buf) | |
| ret void | |
| } | |
| define void @store_out_of_range(double %x) { | |
| ; CHECK-LABEL: store_out_of_range: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: mflr 0 | |
| ; CHECK-NEXT: stwu 1, -272(1) | |
| ; CHECK-NEXT: stw 0, 276(1) | |
| ; CHECK-NEXT: .cfi_def_cfa_offset 272 | |
| ; CHECK-NEXT: .cfi_offset lr, 4 | |
| ; CHECK-NEXT: evmergelo 3, 3, 4 | |
| ; CHECK-NEXT: li 4, 264 | |
| ; CHECK-NEXT: evstddx 3, 1, 4 | |
| ; CHECK-NEXT: addi 3, 1, 16 | |
| ; CHECK-NEXT: bl use | |
| ; CHECK-NEXT: lwz 0, 276(1) | |
| ; CHECK-NEXT: addi 1, 1, 272 | |
| ; CHECK-NEXT: mtlr 0 | |
| ; CHECK-NEXT: blr | |
| %d = alloca double, align 8 | |
| %large = alloca [248 x i8], align 8 | |
| store double %x, ptr %d, align 8 | |
| call void @use(ptr %large) | |
| ret void | |
| } | |
| define double @load_in_range() { | |
| ; CHECK-LABEL: load_in_range: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: mflr 0 | |
| ; CHECK-NEXT: stwu 1, -256(1) | |
| ; CHECK-NEXT: stw 0, 260(1) | |
| ; CHECK-NEXT: .cfi_def_cfa_offset 256 | |
| ; CHECK-NEXT: .cfi_offset lr, 4 | |
| ; CHECK-NEXT: addi 3, 1, 248 | |
| ; CHECK-NEXT: bl use | |
| ; CHECK-NEXT: addi 3, 1, 8 | |
| ; CHECK-NEXT: bl use | |
| ; CHECK-NEXT: evldd 4, 248(1) | |
| ; CHECK-NEXT: evmergehi 3, 4, 4 | |
| ; CHECK-NEXT: lwz 0, 260(1) | |
| ; CHECK-NEXT: addi 1, 1, 256 | |
| ; CHECK-NEXT: mtlr 0 | |
| ; CHECK-NEXT: blr | |
| %d = alloca double, align 8 | |
| %large = alloca [240 x i8], align 8 | |
| call void @use(ptr %d) | |
| call void @use(ptr %large) | |
| %v = load double, ptr %d, align 8 | |
| ret double %v | |
| } | |
| define double @load_unaligned_in_range() { | |
| ; CHECK-LABEL: load_unaligned_in_range: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: mflr 0 | |
| ; CHECK-NEXT: stwu 1, -32(1) | |
| ; CHECK-NEXT: stw 0, 36(1) | |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 | |
| ; CHECK-NEXT: .cfi_offset lr, 4 | |
| ; CHECK-NEXT: addi 3, 1, 16 | |
| ; CHECK-NEXT: bl use | |
| ; CHECK-NEXT: lwz 3, 17(1) | |
| ; CHECK-NEXT: stw 3, 8(1) | |
| ; CHECK-NEXT: lwz 3, 21(1) | |
| ; CHECK-NEXT: stw 3, 12(1) | |
| ; CHECK-NEXT: evldd 4, 8(1) | |
| ; CHECK-NEXT: evmergehi 3, 4, 4 | |
| ; CHECK-NEXT: lwz 0, 36(1) | |
| ; CHECK-NEXT: addi 1, 1, 32 | |
| ; CHECK-NEXT: mtlr 0 | |
| ; CHECK-NEXT: blr | |
| %buf = alloca [16 x i8], align 8 | |
| %p = getelementptr i8, ptr %buf, i32 1 | |
| call void @use(ptr %buf) | |
| %v = load double, ptr %p, align 1 | |
| ret double %v | |
| } | |
| define double @load_unaligned_offset_248() { | |
| ; CHECK-LABEL: load_unaligned_offset_248: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: mflr 0 | |
| ; CHECK-NEXT: stwu 1, -272(1) | |
| ; CHECK-NEXT: stw 0, 276(1) | |
| ; CHECK-NEXT: .cfi_def_cfa_offset 272 | |
| ; CHECK-NEXT: .cfi_offset lr, 4 | |
| ; CHECK-NEXT: addi 3, 1, 16 | |
| ; CHECK-NEXT: bl use | |
| ; CHECK-NEXT: lwz 3, 265(1) | |
| ; CHECK-NEXT: stw 3, 8(1) | |
| ; CHECK-NEXT: lwz 3, 269(1) | |
| ; CHECK-NEXT: stw 3, 12(1) | |
| ; CHECK-NEXT: evldd 4, 8(1) | |
| ; CHECK-NEXT: evmergehi 3, 4, 4 | |
| ; CHECK-NEXT: lwz 0, 276(1) | |
| ; CHECK-NEXT: addi 1, 1, 272 | |
| ; CHECK-NEXT: mtlr 0 | |
| ; CHECK-NEXT: blr | |
| %buf = alloca [256 x i8], align 8 | |
| %p = getelementptr i8, ptr %buf, i32 249 | |
| call void @use(ptr %buf) | |
| %v = load double, ptr %p, align 1 | |
| ret double %v | |
| } | |
| define double @load_out_of_range() { | |
| ; CHECK-LABEL: load_out_of_range: | |
| ; CHECK: # %bb.0: | |
| ; CHECK-NEXT: mflr 0 | |
| ; CHECK-NEXT: stwu 1, -272(1) | |
| ; CHECK-NEXT: stw 0, 276(1) | |
| ; CHECK-NEXT: .cfi_def_cfa_offset 272 | |
| ; CHECK-NEXT: .cfi_offset lr, 4 | |
| ; CHECK-NEXT: addi 3, 1, 264 | |
| ; CHECK-NEXT: bl use | |
| ; CHECK-NEXT: addi 3, 1, 16 | |
| ; CHECK-NEXT: bl use | |
| ; CHECK-NEXT: li 3, 264 | |
| ; CHECK-NEXT: evlddx 4, 1, 3 | |
| ; CHECK-NEXT: evmergehi 3, 4, 4 | |
| ; CHECK-NEXT: lwz 0, 276(1) | |
| ; CHECK-NEXT: addi 1, 1, 272 | |
| ; CHECK-NEXT: mtlr 0 | |
| ; CHECK-NEXT: blr | |
| %d = alloca double, align 8 | |
| %large = alloca [248 x i8], align 8 | |
| call void @use(ptr %d) | |
| call void @use(ptr %large) | |
| %v = load double, ptr %d, align 8 | |
| ret double %v | |
| } |