1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=mips-linux-gnu -relocation-model=static < %s \ 3; RUN: | FileCheck --check-prefixes=O32,O32-BE %s 4; RUN: llc -mtriple=mipsel-linux-gnu -relocation-model=static < %s \ 5; RUN: | FileCheck --check-prefixes=O32,O32-LE %s 6 7; RUN-TODO: llc -mtriple=mips64-linux-gnu -relocation-model=static -target-abi o32 < %s \ 8; RUN-TODO: | FileCheck --check-prefixes=O32 %s 9; RUN-TODO: llc -mtriple=mips64el-linux-gnu -relocation-model=static -target-abi o32 < %s \ 10; RUN-TODO: | FileCheck --check-prefixes=O32 %s 11 12; RUN: llc -mtriple=mips64-linux-gnu -relocation-model=static -target-abi n32 < %s \ 13; RUN: | FileCheck --check-prefixes=N32,N32-BE %s 14; RUN: llc -mtriple=mips64el-linux-gnu -relocation-model=static -target-abi n32 < %s \ 15; RUN: | FileCheck --check-prefixes=N32,N32-LE %s 16 17; RUN: llc -mtriple=mips64-linux-gnu -relocation-model=static -target-abi n64 < %s \ 18; RUN: | FileCheck --check-prefixes=N64,N64-BE %s 19; RUN: llc -mtriple=mips64el-linux-gnu -relocation-model=static -target-abi n64 < %s \ 20; RUN: | FileCheck --check-prefixes=N64,N64-LE %s 21 22; Test struct returns for all ABI's and byte orders. 23 24@struct_byte = global {i8} zeroinitializer 25@struct_2byte = global {i8,i8} zeroinitializer 26@struct_3xi16 = global {[3 x i16]} zeroinitializer 27@struct_6xi32 = global {[6 x i32]} zeroinitializer 28@struct_128xi16 = global {[128 x i16]} zeroinitializer 29 30declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture readonly, i64, i1) 31 32define inreg {i8} @ret_struct_i8() nounwind { 33; O32-LABEL: ret_struct_i8: 34; O32: # %bb.0: # %entry 35; O32-NEXT: lui $1, %hi(struct_byte) 36; O32-NEXT: jr $ra 37; O32-NEXT: lbu $2, %lo(struct_byte)($1) 38; 39; N32-BE-LABEL: ret_struct_i8: 40; N32-BE: # %bb.0: # %entry 41; N32-BE-NEXT: lui $1, %hi(struct_byte) 42; N32-BE-NEXT: lb $1, %lo(struct_byte)($1) 43; N32-BE-NEXT: jr $ra 44; N32-BE-NEXT: dsll $2, $1, 56 45; 46; N32-LE-LABEL: ret_struct_i8: 47; N32-LE: # %bb.0: # %entry 48; N32-LE-NEXT: lui $1, %hi(struct_byte) 49; N32-LE-NEXT: jr $ra 50; N32-LE-NEXT: lb $2, %lo(struct_byte)($1) 51; 52; N64-BE-LABEL: ret_struct_i8: 53; N64-BE: # %bb.0: # %entry 54; N64-BE-NEXT: lui $1, %highest(struct_byte) 55; N64-BE-NEXT: daddiu $1, $1, %higher(struct_byte) 56; N64-BE-NEXT: dsll $1, $1, 16 57; N64-BE-NEXT: daddiu $1, $1, %hi(struct_byte) 58; N64-BE-NEXT: dsll $1, $1, 16 59; N64-BE-NEXT: lb $1, %lo(struct_byte)($1) 60; N64-BE-NEXT: jr $ra 61; N64-BE-NEXT: dsll $2, $1, 56 62; 63; N64-LE-LABEL: ret_struct_i8: 64; N64-LE: # %bb.0: # %entry 65; N64-LE-NEXT: lui $1, %highest(struct_byte) 66; N64-LE-NEXT: daddiu $1, $1, %higher(struct_byte) 67; N64-LE-NEXT: dsll $1, $1, 16 68; N64-LE-NEXT: daddiu $1, $1, %hi(struct_byte) 69; N64-LE-NEXT: dsll $1, $1, 16 70; N64-LE-NEXT: jr $ra 71; N64-LE-NEXT: lb $2, %lo(struct_byte)($1) 72entry: 73 %0 = load volatile {i8}, ptr @struct_byte 74 ret {i8} %0 75} 76 77; This test is based on the way clang currently lowers {i8,i8} to {i16}. 78; FIXME: It should probably work for without any lowering too but this doesn't 79; work as expected. Each member gets mapped to a register rather than 80; packed into a single register. 81define inreg {i16} @ret_struct_i16() nounwind { 82; O32-LABEL: ret_struct_i16: 83; O32: # %bb.0: # %entry 84; O32-NEXT: addiu $sp, $sp, -8 85; O32-NEXT: lui $1, %hi(struct_2byte) 86; O32-NEXT: lhu $1, %lo(struct_2byte)($1) 87; O32-NEXT: sh $1, 0($sp) 88; O32-NEXT: lhu $2, 0($sp) 89; O32-NEXT: jr $ra 90; O32-NEXT: addiu $sp, $sp, 8 91; 92; N32-BE-LABEL: ret_struct_i16: 93; N32-BE: # %bb.0: # %entry 94; N32-BE-NEXT: addiu $sp, $sp, -16 95; N32-BE-NEXT: lui $1, %hi(struct_2byte) 96; N32-BE-NEXT: lhu $1, %lo(struct_2byte)($1) 97; N32-BE-NEXT: sh $1, 8($sp) 98; N32-BE-NEXT: lh $1, 8($sp) 99; N32-BE-NEXT: dsll $2, $1, 48 100; N32-BE-NEXT: jr $ra 101; N32-BE-NEXT: addiu $sp, $sp, 16 102; 103; N32-LE-LABEL: ret_struct_i16: 104; N32-LE: # %bb.0: # %entry 105; N32-LE-NEXT: addiu $sp, $sp, -16 106; N32-LE-NEXT: lui $1, %hi(struct_2byte) 107; N32-LE-NEXT: lhu $1, %lo(struct_2byte)($1) 108; N32-LE-NEXT: sh $1, 8($sp) 109; N32-LE-NEXT: lh $2, 8($sp) 110; N32-LE-NEXT: jr $ra 111; N32-LE-NEXT: addiu $sp, $sp, 16 112; 113; N64-BE-LABEL: ret_struct_i16: 114; N64-BE: # %bb.0: # %entry 115; N64-BE-NEXT: daddiu $sp, $sp, -16 116; N64-BE-NEXT: lui $1, %highest(struct_2byte) 117; N64-BE-NEXT: daddiu $1, $1, %higher(struct_2byte) 118; N64-BE-NEXT: dsll $1, $1, 16 119; N64-BE-NEXT: daddiu $1, $1, %hi(struct_2byte) 120; N64-BE-NEXT: dsll $1, $1, 16 121; N64-BE-NEXT: lhu $1, %lo(struct_2byte)($1) 122; N64-BE-NEXT: sh $1, 8($sp) 123; N64-BE-NEXT: lh $1, 8($sp) 124; N64-BE-NEXT: dsll $2, $1, 48 125; N64-BE-NEXT: jr $ra 126; N64-BE-NEXT: daddiu $sp, $sp, 16 127; 128; N64-LE-LABEL: ret_struct_i16: 129; N64-LE: # %bb.0: # %entry 130; N64-LE-NEXT: daddiu $sp, $sp, -16 131; N64-LE-NEXT: lui $1, %highest(struct_2byte) 132; N64-LE-NEXT: daddiu $1, $1, %higher(struct_2byte) 133; N64-LE-NEXT: dsll $1, $1, 16 134; N64-LE-NEXT: daddiu $1, $1, %hi(struct_2byte) 135; N64-LE-NEXT: dsll $1, $1, 16 136; N64-LE-NEXT: lhu $1, %lo(struct_2byte)($1) 137; N64-LE-NEXT: sh $1, 8($sp) 138; N64-LE-NEXT: lh $2, 8($sp) 139; N64-LE-NEXT: jr $ra 140; N64-LE-NEXT: daddiu $sp, $sp, 16 141entry: 142 %retval = alloca {i8,i8}, align 8 143 call void @llvm.memcpy.p0.p0.i64(ptr %retval, ptr @struct_2byte, i64 2, i1 false) 144 %0 = load volatile {i16}, ptr %retval 145 ret {i16} %0 146} 147 148; Ensure that structures bigger than 32-bits but smaller than 64-bits are 149; also returned in the upper bits on big endian targets. Previously, these were 150; missed by the CCPromoteToType and the shift didn't happen. 151define inreg {i48} @ret_struct_3xi16() nounwind { 152; O32-BE-LABEL: ret_struct_3xi16: 153; O32-BE: # %bb.0: # %entry 154; O32-BE-NEXT: lui $1, %hi(struct_3xi16) 155; O32-BE-NEXT: lw $2, %lo(struct_3xi16)($1) 156; O32-BE-NEXT: sll $3, $2, 16 157; O32-BE-NEXT: addiu $1, $1, %lo(struct_3xi16) 158; O32-BE-NEXT: lhu $1, 4($1) 159; O32-BE-NEXT: or $3, $1, $3 160; O32-BE-NEXT: jr $ra 161; O32-BE-NEXT: srl $2, $2, 16 162; 163; O32-LE-LABEL: ret_struct_3xi16: 164; O32-LE: # %bb.0: # %entry 165; O32-LE-NEXT: lui $1, %hi(struct_3xi16) 166; O32-LE-NEXT: lw $2, %lo(struct_3xi16)($1) 167; O32-LE-NEXT: addiu $1, $1, %lo(struct_3xi16) 168; O32-LE-NEXT: jr $ra 169; O32-LE-NEXT: lhu $3, 4($1) 170; 171; N32-BE-LABEL: ret_struct_3xi16: 172; N32-BE: # %bb.0: # %entry 173; N32-BE-NEXT: lui $1, %hi(struct_3xi16) 174; N32-BE-NEXT: lw $2, %lo(struct_3xi16)($1) 175; N32-BE-NEXT: dsll $2, $2, 32 176; N32-BE-NEXT: addiu $1, $1, %lo(struct_3xi16) 177; N32-BE-NEXT: lhu $1, 4($1) 178; N32-BE-NEXT: dsll $1, $1, 16 179; N32-BE-NEXT: jr $ra 180; N32-BE-NEXT: or $2, $2, $1 181; 182; N32-LE-LABEL: ret_struct_3xi16: 183; N32-LE: # %bb.0: # %entry 184; N32-LE-NEXT: lui $1, %hi(struct_3xi16) 185; N32-LE-NEXT: lwu $2, %lo(struct_3xi16)($1) 186; N32-LE-NEXT: addiu $1, $1, %lo(struct_3xi16) 187; N32-LE-NEXT: lh $1, 4($1) 188; N32-LE-NEXT: dsll $1, $1, 32 189; N32-LE-NEXT: jr $ra 190; N32-LE-NEXT: or $2, $2, $1 191; 192; N64-BE-LABEL: ret_struct_3xi16: 193; N64-BE: # %bb.0: # %entry 194; N64-BE-NEXT: lui $1, %highest(struct_3xi16) 195; N64-BE-NEXT: daddiu $1, $1, %higher(struct_3xi16) 196; N64-BE-NEXT: dsll $1, $1, 16 197; N64-BE-NEXT: daddiu $1, $1, %hi(struct_3xi16) 198; N64-BE-NEXT: dsll $1, $1, 16 199; N64-BE-NEXT: lw $2, %lo(struct_3xi16)($1) 200; N64-BE-NEXT: dsll $2, $2, 32 201; N64-BE-NEXT: daddiu $1, $1, %lo(struct_3xi16) 202; N64-BE-NEXT: lhu $1, 4($1) 203; N64-BE-NEXT: dsll $1, $1, 16 204; N64-BE-NEXT: jr $ra 205; N64-BE-NEXT: or $2, $2, $1 206; 207; N64-LE-LABEL: ret_struct_3xi16: 208; N64-LE: # %bb.0: # %entry 209; N64-LE-NEXT: lui $1, %highest(struct_3xi16) 210; N64-LE-NEXT: daddiu $1, $1, %higher(struct_3xi16) 211; N64-LE-NEXT: dsll $1, $1, 16 212; N64-LE-NEXT: daddiu $1, $1, %hi(struct_3xi16) 213; N64-LE-NEXT: dsll $1, $1, 16 214; N64-LE-NEXT: lwu $2, %lo(struct_3xi16)($1) 215; N64-LE-NEXT: daddiu $1, $1, %lo(struct_3xi16) 216; N64-LE-NEXT: lh $1, 4($1) 217; N64-LE-NEXT: dsll $1, $1, 32 218; N64-LE-NEXT: jr $ra 219; N64-LE-NEXT: or $2, $2, $1 220entry: 221 %0 = load volatile i48, ptr @struct_3xi16, align 2 222 %1 = insertvalue {i48} undef, i48 %0, 0 223 ret {i48} %1 224} 225 226; Ensure that large structures (>128-bit) are returned indirectly. 227; We pick an extremely large structure so we don't have to match inlined memcpy's. 228define void @ret_struct_128xi16(ptr sret({[128 x i16]}) %returnval) { 229; O32-LABEL: ret_struct_128xi16: 230; O32: # %bb.0: # %entry 231; O32-NEXT: addiu $sp, $sp, -24 232; O32-NEXT: .cfi_def_cfa_offset 24 233; O32-NEXT: sw $ra, 20($sp) # 4-byte Folded Spill 234; O32-NEXT: sw $16, 16($sp) # 4-byte Folded Spill 235; O32-NEXT: .cfi_offset 31, -4 236; O32-NEXT: .cfi_offset 16, -8 237; O32-NEXT: move $16, $4 238; O32-NEXT: lui $1, %hi(struct_128xi16) 239; O32-NEXT: addiu $5, $1, %lo(struct_128xi16) 240; O32-NEXT: jal memcpy 241; O32-NEXT: addiu $6, $zero, 256 242; O32-NEXT: move $2, $16 243; O32-NEXT: lw $16, 16($sp) # 4-byte Folded Reload 244; O32-NEXT: lw $ra, 20($sp) # 4-byte Folded Reload 245; O32-NEXT: jr $ra 246; O32-NEXT: addiu $sp, $sp, 24 247; 248; N32-LABEL: ret_struct_128xi16: 249; N32: # %bb.0: # %entry 250; N32-NEXT: addiu $sp, $sp, -16 251; N32-NEXT: .cfi_def_cfa_offset 16 252; N32-NEXT: sd $ra, 8($sp) # 8-byte Folded Spill 253; N32-NEXT: sd $16, 0($sp) # 8-byte Folded Spill 254; N32-NEXT: .cfi_offset 31, -8 255; N32-NEXT: .cfi_offset 16, -16 256; N32-NEXT: lui $1, %hi(struct_128xi16) 257; N32-NEXT: addiu $5, $1, %lo(struct_128xi16) 258; N32-NEXT: sll $16, $4, 0 259; N32-NEXT: jal memcpy 260; N32-NEXT: daddiu $6, $zero, 256 261; N32-NEXT: move $2, $16 262; N32-NEXT: ld $16, 0($sp) # 8-byte Folded Reload 263; N32-NEXT: ld $ra, 8($sp) # 8-byte Folded Reload 264; N32-NEXT: jr $ra 265; N32-NEXT: addiu $sp, $sp, 16 266; 267; N64-LABEL: ret_struct_128xi16: 268; N64: # %bb.0: # %entry 269; N64-NEXT: daddiu $sp, $sp, -16 270; N64-NEXT: .cfi_def_cfa_offset 16 271; N64-NEXT: sd $ra, 8($sp) # 8-byte Folded Spill 272; N64-NEXT: sd $16, 0($sp) # 8-byte Folded Spill 273; N64-NEXT: .cfi_offset 31, -8 274; N64-NEXT: .cfi_offset 16, -16 275; N64-NEXT: move $16, $4 276; N64-NEXT: lui $1, %highest(struct_128xi16) 277; N64-NEXT: daddiu $1, $1, %higher(struct_128xi16) 278; N64-NEXT: dsll $1, $1, 16 279; N64-NEXT: daddiu $1, $1, %hi(struct_128xi16) 280; N64-NEXT: dsll $1, $1, 16 281; N64-NEXT: daddiu $5, $1, %lo(struct_128xi16) 282; N64-NEXT: jal memcpy 283; N64-NEXT: daddiu $6, $zero, 256 284; N64-NEXT: move $2, $16 285; N64-NEXT: ld $16, 0($sp) # 8-byte Folded Reload 286; N64-NEXT: ld $ra, 8($sp) # 8-byte Folded Reload 287; N64-NEXT: jr $ra 288; N64-NEXT: daddiu $sp, $sp, 16 289entry: 290 call void @llvm.memcpy.p0.p0.i64(ptr align 2 %returnval, ptr align 2 @struct_128xi16, i64 256, i1 false) 291 ret void 292} 293 294; Ensure that large structures (>128-bit) are returned indirectly. 295; This will generate inlined memcpy's anyway so pick the smallest large 296; structure 297; This time we let the backend lower the sret argument. 298define {[6 x i32]} @ret_struct_6xi32() { 299; O32-LABEL: ret_struct_6xi32: 300; O32: # %bb.0: # %entry 301; O32-NEXT: lui $1, %hi(struct_6xi32) 302; O32-NEXT: lw $2, %lo(struct_6xi32)($1) 303; O32-NEXT: addiu $1, $1, %lo(struct_6xi32) 304; O32-NEXT: lw $3, 4($1) 305; O32-NEXT: lw $5, 8($1) 306; O32-NEXT: lw $6, 12($1) 307; O32-NEXT: lw $7, 16($1) 308; O32-NEXT: lw $1, 20($1) 309; O32-NEXT: sw $1, 20($4) 310; O32-NEXT: sw $7, 16($4) 311; O32-NEXT: sw $6, 12($4) 312; O32-NEXT: sw $5, 8($4) 313; O32-NEXT: sw $3, 4($4) 314; O32-NEXT: jr $ra 315; O32-NEXT: sw $2, 0($4) 316; 317; N32-LABEL: ret_struct_6xi32: 318; N32: # %bb.0: # %entry 319; N32-NEXT: sll $1, $4, 0 320; N32-NEXT: lui $2, %hi(struct_6xi32) 321; N32-NEXT: lw $3, %lo(struct_6xi32)($2) 322; N32-NEXT: addiu $2, $2, %lo(struct_6xi32) 323; N32-NEXT: lw $4, 4($2) 324; N32-NEXT: lw $5, 8($2) 325; N32-NEXT: lw $6, 12($2) 326; N32-NEXT: lw $7, 16($2) 327; N32-NEXT: lw $2, 20($2) 328; N32-NEXT: sw $2, 20($1) 329; N32-NEXT: sw $7, 16($1) 330; N32-NEXT: sw $6, 12($1) 331; N32-NEXT: sw $5, 8($1) 332; N32-NEXT: sw $4, 4($1) 333; N32-NEXT: jr $ra 334; N32-NEXT: sw $3, 0($1) 335; 336; N64-LABEL: ret_struct_6xi32: 337; N64: # %bb.0: # %entry 338; N64-NEXT: lui $1, %highest(struct_6xi32) 339; N64-NEXT: daddiu $1, $1, %higher(struct_6xi32) 340; N64-NEXT: dsll $1, $1, 16 341; N64-NEXT: daddiu $1, $1, %hi(struct_6xi32) 342; N64-NEXT: dsll $1, $1, 16 343; N64-NEXT: lw $2, %lo(struct_6xi32)($1) 344; N64-NEXT: daddiu $1, $1, %lo(struct_6xi32) 345; N64-NEXT: lw $3, 4($1) 346; N64-NEXT: lw $5, 8($1) 347; N64-NEXT: lw $6, 12($1) 348; N64-NEXT: lw $7, 16($1) 349; N64-NEXT: lw $1, 20($1) 350; N64-NEXT: sw $1, 20($4) 351; N64-NEXT: sw $7, 16($4) 352; N64-NEXT: sw $6, 12($4) 353; N64-NEXT: sw $5, 8($4) 354; N64-NEXT: sw $3, 4($4) 355; N64-NEXT: jr $ra 356; N64-NEXT: sw $2, 0($4) 357entry: 358 %0 = load volatile {[6 x i32]}, ptr @struct_6xi32, align 2 359 ret {[6 x i32]} %0 360} 361