blob: fcc939f879cc5ad08f40f46ca39f56464ca7fcaf [file] [log] [blame]
; This tries to be a comprehensive test of i8 operations.
; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 \
; RUN: -allow-externally-defined-symbols | FileCheck %s
; RUN: %p2i --filetype=obj --disassemble -i %s --args -Om1 \
; RUN: -allow-externally-defined-symbols | FileCheck %s
; The following tests i8 srem/urem lowering on x86-64, specifically that the %ah
; result gets copied into %al/%bl/%cl/%dl before moved into its final register.
; This extra copy is forced by excluding al/bl/cl/dl by default (-reg-exclude),
; but allowing them to be used if absolutely necessary (-reg-reserve).
; RUN: %p2i --target=x8664 --filetype=obj --disassemble -i %s --args -O2 \
; RUN: -reg-exclude=al,bl,cl,dl -reg-reserve \
; RUN: -allow-externally-defined-symbols | FileCheck %s --check-prefix=REM
; RUN: %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command %p2i --filetype=asm --assemble --disassemble --target \
; RUN: mips32 -i %s --args -O2 -allow-externally-defined-symbols \
; RUN: | %if --need=target_MIPS32 --need=allow_dump \
; RUN: --command FileCheck --check-prefix MIPS32 %s
declare void @useInt(i32 %x)
define internal i32 @add8Bit(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%b_8 = trunc i32 %b to i8
%add = add i8 %b_8, %a_8
%ret = zext i8 %add to i32
ret i32 %ret
}
; CHECK-LABEL: add8Bit
; CHECK: add {{[abcd]l}}
; MIPS32-LABEL: add8Bit
; MIPS32: addu
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @add8BitConst(i32 %a) {
entry:
%a_8 = trunc i32 %a to i8
%add = add i8 %a_8, 123
%ret = zext i8 %add to i32
ret i32 %ret
}
; CHECK-LABEL: add8BitConst
; CHECK: add {{[abcd]l}}
; MIPS32-LABEL: add8BitConst
; MIPS32: addiu
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @sub8Bit(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%b_8 = trunc i32 %b to i8
%sub = sub i8 %b_8, %a_8
%ret = zext i8 %sub to i32
ret i32 %ret
}
; CHECK-LABEL: sub8Bit
; CHECK: sub {{[abcd]l}}
; MIPS32-LABEL: sub8Bit
; MIPS32: subu
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @sub8BitConst(i32 %a) {
entry:
%a_8 = trunc i32 %a to i8
%sub = sub i8 %a_8, 123
%ret = zext i8 %sub to i32
ret i32 %ret
}
; CHECK-LABEL: sub8BitConst
; CHECK: sub {{[abcd]l}}
; MIPS32-LABEL: sub8BitConst
; MIPS32: addiu {{.*}},-123
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @mul8Bit(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%b_8 = trunc i32 %b to i8
%mul = mul i8 %b_8, %a_8
%ret = zext i8 %mul to i32
ret i32 %ret
}
; CHECK-LABEL: mul8Bit
; CHECK: mul {{[abcd]l|BYTE PTR}}
; MIPS32-LABEL: mul8Bit
; MIPS32: mul
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @mul8BitConst(i32 %a) {
entry:
%a_8 = trunc i32 %a to i8
%mul = mul i8 %a_8, 56
%ret = zext i8 %mul to i32
ret i32 %ret
}
; CHECK-LABEL: mul8BitConst
; 8-bit imul only accepts r/m, not imm
; CHECK: mov {{.*}},0x38
; CHECK: mul {{[abcd]l|BYTE PTR}}
; MIPS32-LABEL: mul8BitConst
; MIPS32: li
; MIPS32: mul
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @udiv8Bit(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%b_8 = trunc i32 %b to i8
%udiv = udiv i8 %b_8, %a_8
%ret = zext i8 %udiv to i32
ret i32 %ret
}
; CHECK-LABEL: udiv8Bit
; CHECK: div {{[abcd]l|BYTE PTR}}
; MIPS32-LABEL: udiv8Bit
; MIPS32: divu
; MIPS32: teq
; MIPS32: mflo
; MIPS32: andi {{.*}},0xff
; MIPS32: jr
; MIPS32: nop
define internal i32 @udiv8BitConst(i32 %a) {
entry:
%a_8 = trunc i32 %a to i8
%udiv = udiv i8 %a_8, 123
%ret = zext i8 %udiv to i32
ret i32 %ret
}
; CHECK-LABEL: udiv8BitConst
; CHECK: div {{[abcd]l|BYTE PTR}}
; MIPS32-LABEL: udiv8BitConst
; MIPS32: li
; MIPS32: divu
; MIPS32: teq
; MIPS32: mflo
; MIPS32: andi {{.*}},0xff
; MIPS32: jr
; MIPS32: nop
define internal i32 @urem8Bit(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%b_8 = trunc i32 %b to i8
%urem = urem i8 %b_8, %a_8
%ret = zext i8 %urem to i32
ret i32 %ret
}
; CHECK-LABEL: urem8Bit
; CHECK: div {{[abcd]l|BYTE PTR}}
; REM-LABEL: urem8Bit
; REM: div
; REM-NEXT: mov {{[abcd]}}l,ah
; MIPS32-LABEL: urem8Bit
; MIPS32: divu
; MIPS32: teq
; MIPS32: mfhi
; MIPS32: andi {{.*}},0xff
; MIPS32: jr
; MIPS32: nop
define internal i32 @urem8BitConst(i32 %a) {
entry:
%a_8 = trunc i32 %a to i8
%urem = urem i8 %a_8, 123
%ret = zext i8 %urem to i32
ret i32 %ret
}
; CHECK-LABEL: urem8BitConst
; CHECK: div {{[abcd]l|BYTE PTR}}
; REM-LABEL: urem8BitConst
; MIPS32-LABEL: urem8BitConst
; MIPS32: li
; MIPS32: divu
; MIPS32: teq
; MIPS32: mfhi
; MIPS32: andi {{.*}},0xff
; MIPS32: jr
; MIPS32: nop
define internal i32 @sdiv8Bit(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%b_8 = trunc i32 %b to i8
%sdiv = sdiv i8 %b_8, %a_8
%ret = zext i8 %sdiv to i32
ret i32 %ret
}
; CHECK-LABEL: sdiv8Bit
; CHECK: idiv {{[abcd]l|BYTE PTR}}
; MIPS32-LABEL: sdiv8Bit
; MIPS32: div
; MIPS32: teq
; MIPS32: mflo
; MIPS32: andi {{.*}},0xff
; MIPS32: jr
; MIPS32: nop
define internal i32 @sdiv8BitConst(i32 %a) {
entry:
%a_8 = trunc i32 %a to i8
%sdiv = sdiv i8 %a_8, 123
%ret = zext i8 %sdiv to i32
ret i32 %ret
}
; CHECK-LABEL: sdiv8BitConst
; CHECK: idiv {{[abcd]l|BYTE PTR}}
; MIPS32-LABEL: sdiv8BitConst
; MIPS32: li
; MIPS32: div
; MIPS32: teq
; MIPS32: mflo
; MIPS32: andi {{.*}},0xff
; MIPS32: jr
; MIPS32: nop
define internal i32 @srem8Bit(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%b_8 = trunc i32 %b to i8
%srem = srem i8 %b_8, %a_8
%ret = zext i8 %srem to i32
ret i32 %ret
}
; CHECK-LABEL: srem8Bit
; CHECK: idiv {{[abcd]l|BYTE PTR}}
; REM-LABEL: srem8Bit
; REM: idiv
; REM-NEXT: mov {{[abcd]}}l,ah
; MIPS32-LABEL: srem8Bit
; MIPS32: div
; MIPS32: teq
; MIPS32: mfhi
; MIPS32: andi {{.*}},0xff
; MIPS32: jr
; MIPS32: nop
define internal i32 @srem8BitConst(i32 %a) {
entry:
%a_8 = trunc i32 %a to i8
%srem = srem i8 %a_8, 123
%ret = zext i8 %srem to i32
ret i32 %ret
}
; CHECK-LABEL: srem8BitConst
; CHECK: idiv {{[abcd]l|BYTE PTR}}
; REM-LABEL: srem8BitConst
; MIPS32-LABEL: srem8BitConst
; MIPS32: li
; MIPS32: div
; MIPS32: teq
; MIPS32: mfhi
; MIPS32: andi {{.*}},0xff
; MIPS32: jr
; MIPS32: nop
define internal i32 @shl8Bit(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%b_8 = trunc i32 %b to i8
%shl = shl i8 %b_8, %a_8
%ret = zext i8 %shl to i32
ret i32 %ret
}
; CHECK-LABEL: shl8Bit
; CHECK: shl {{[abd]l|BYTE PTR}},cl
; MIPS32-LABEL: shl8Bit
; MIPS32: sllv
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @shl8BitConst(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%shl = shl i8 %a_8, 6
%ret = zext i8 %shl to i32
ret i32 %ret
}
; CHECK-LABEL: shl8BitConst
; CHECK: shl {{[abcd]l|BYTE PTR}},0x6
; MIPS32-LABEL: shl8BitConst
; MIPS32: sll
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @lshr8Bit(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%b_8 = trunc i32 %b to i8
%lshr = lshr i8 %b_8, %a_8
%ret = zext i8 %lshr to i32
ret i32 %ret
}
; CHECK-LABEL: lshr8Bit
; CHECK: shr {{[abd]l|BYTE PTR}},cl
; MIPS32-LABEL: lshr8Bit
; MIPS32: srlv
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @lshr8BitConst(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%lshr = lshr i8 %a_8, 6
%ret = zext i8 %lshr to i32
ret i32 %ret
}
; CHECK-LABEL: lshr8BitConst
; CHECK: shr {{[abcd]l|BYTE PTR}},0x6
; MIPS32-LABEL: lshr8BitConst
; MIPS32: srl
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @ashr8Bit(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%b_8 = trunc i32 %b to i8
%ashr = ashr i8 %b_8, %a_8
%ret = zext i8 %ashr to i32
ret i32 %ret
}
; CHECK-LABEL: ashr8Bit
; CHECK: sar {{[abd]l|BYTE PTR}},cl
; MIPS32-LABEL: ashr8Bit
; MIPS32: sra
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @ashr8BitConst(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%ashr = ashr i8 %a_8, 6
%ret = zext i8 %ashr to i32
ret i32 %ret
}
; CHECK-LABEL: ashr8BitConst
; CHECK: sar {{[abcd]l|BYTE PTR}},0x6
; MIPS32-LABEL: ashr8BitConst
; MIPS32: sra
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @icmp8Bit(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%b_8 = trunc i32 %b to i8
%icmp = icmp ne i8 %b_8, %a_8
%ret = zext i1 %icmp to i32
ret i32 %ret
}
; CHECK-LABEL: icmp8Bit
; CHECK: cmp {{[abcd]l|BYTE PTR}}
; MIPS32-LABEL: icmp8Bit
; MIPS32: sll {{.*}},0x18
; MIPS32: sll {{.*}},0x18
; MIPS32: xor
; MIPS32: sltu
; MIPS32: andi {{.*}},0x1
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @icmp8BitConst(i32 %a) {
entry:
%a_8 = trunc i32 %a to i8
%icmp = icmp ne i8 %a_8, 123
%ret = zext i1 %icmp to i32
ret i32 %ret
}
; CHECK-LABEL: icmp8BitConst
; CHECK: cmp {{[abcd]l|BYTE PTR}}
; MIPS32-LABEL: icmp8BitConst
; MIPS32: li
; MIPS32: sll {{.*}},0x18
; MIPS32: sll {{.*}},0x18
; MIPS32: xor
; MIPS32: sltu
; MIPS32: andi {{.*}},0x1
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @icmp8BitConstSwapped(i32 %a) {
entry:
%a_8 = trunc i32 %a to i8
%icmp = icmp ne i8 123, %a_8
%ret = zext i1 %icmp to i32
ret i32 %ret
}
; CHECK-LABEL: icmp8BitConstSwapped
; CHECK: cmp {{[abcd]l|BYTE PTR}}
; MIPS32-LABEL: icmp8BitConstSwapped
; MIPS32: li
; MIPS32: sll {{.*}},0x18
; MIPS32: sll {{.*}},0x18
; MIPS32: xor v0,v0,a0
; MIPS32: sltu
; MIPS32: andi {{.*}},0x1
; MIPS32: jr
; MIPS32: nop
define internal i32 @icmp8BitMem(i32 %a, i32 %b_iptr) {
entry:
%a_8 = trunc i32 %a to i8
%bptr = inttoptr i32 %b_iptr to i8*
%b_8 = load i8, i8* %bptr, align 1
%icmp = icmp ne i8 %b_8, %a_8
%ret = zext i1 %icmp to i32
ret i32 %ret
}
; CHECK-LABEL: icmp8BitMem
; CHECK: cmp {{[abcd]l|BYTE PTR}}
; MIPS32-LABEL: icmp8BitMem
; MIPS32: lb
; MIPS32: sll {{.*}},0x18
; MIPS32: sll {{.*}},0x18
; MIPS32: xor
; MIPS32: sltu
; MIPS32: andi {{.*}},0x1
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @icmp8BitMemSwapped(i32 %a, i32 %b_iptr) {
entry:
%a_8 = trunc i32 %a to i8
%bptr = inttoptr i32 %b_iptr to i8*
%b_8 = load i8, i8* %bptr, align 1
%icmp = icmp ne i8 %a_8, %b_8
%ret = zext i1 %icmp to i32
ret i32 %ret
}
; CHECK-LABEL: icmp8BitMemSwapped
; CHECK: cmp {{[abcd]l|BYTE PTR}}
; MIPS32-LABEL: icmp8BitMemSwapped
; MIPS32: lb
; MIPS32: sll {{.*}},0x18
; MIPS32: sll {{.*}},0x18
; MIPS32: xor
; MIPS32: sltu
; MIPS32: andi {{.*}},0x1
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define internal i32 @selectI8Var(i32 %a, i32 %b) {
entry:
%a_8 = trunc i32 %a to i8
%b_8 = trunc i32 %b to i8
%cmp = icmp slt i8 %a_8, %b_8
%ret = select i1 %cmp, i8 %a_8, i8 %b_8
%ret_ext = zext i8 %ret to i32
; Create a "fake" use of %cmp to prevent O2 bool folding.
%d1 = zext i1 %cmp to i32
call void @useInt(i32 %d1)
ret i32 %ret_ext
}
; CHECK-LABEL: selectI8Var
; CHECK: cmp
; CHECK: setl
; CHECK: mov {{[a-d]l}}
; MIPS32-LABEL: selectI8Var
; MIPS32: addiu
; MIPS32: sw
; MIPS32: sw
; MIPS32: move
; MIPS32: move
; MIPS32: sll {{.*}},0x18
; MIPS32: sll {{.*}},0x18
; MIPS32: slt
; MIPS32: move
; MIPS32: movn
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: andi {{.*}},0x1
; MIPS32: move
; MIPS32: jal
; MIPS32: nop
; MIPS32: move
; MIPS32: lw
; MIPS32: lw
; MIPS32: addiu
; MIPS32: jr
; MIPS32: nop
define internal i32 @testPhi8(i32 %arg, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7, i32 %arg8, i32 %arg9, i32 %arg10) {
entry:
%trunc = trunc i32 %arg to i8
%trunc2 = trunc i32 %arg2 to i8
%trunc3 = trunc i32 %arg3 to i8
%trunc4 = trunc i32 %arg4 to i8
%trunc5 = trunc i32 %arg5 to i8
%cmp1 = icmp sgt i32 %arg, 0
br i1 %cmp1, label %next, label %target
next:
%trunc6_16 = trunc i32 %arg6 to i16
%trunc7_16 = trunc i32 %arg7 to i16
%trunc8_16 = trunc i32 %arg8 to i16
%trunc9 = trunc i32 %arg9 to i8
%trunc10 = trunc i32 %arg10 to i8
%trunc7_8 = trunc i16 %trunc7_16 to i8
%trunc6_8 = trunc i16 %trunc6_16 to i8
%trunc8_8 = trunc i16 %trunc8_16 to i8
br label %target
target:
%merge1 = phi i1 [ %cmp1, %entry ], [ false, %next ]
%merge2 = phi i8 [ %trunc, %entry ], [ %trunc6_8, %next ]
%merge3 = phi i8 [ %trunc2, %entry ], [ %trunc7_8, %next ]
%merge5 = phi i8 [ %trunc4, %entry ], [ %trunc9, %next ]
%merge6 = phi i8 [ %trunc5, %entry ], [ %trunc10, %next ]
%merge4 = phi i8 [ %trunc3, %entry ], [ %trunc8_8, %next ]
%res1 = select i1 %merge1, i8 %merge2, i8 %merge3
%res2 = select i1 %merge1, i8 %merge4, i8 %merge5
%res1_2 = select i1 %merge1, i8 %res1, i8 %res2
%res123 = select i1 %merge1, i8 %merge6, i8 %res1_2
%result = zext i8 %res123 to i32
ret i32 %result
}
; CHECK-LABEL: testPhi8
; This assumes there will be some copy from an 8-bit register / stack slot.
; CHECK-DAG: mov {{.*}},{{[a-d]}}l
; CHECK-DAG: mov {{.*}},BYTE PTR
; CHECK-DAG: mov BYTE PTR {{.*}}
@global8 = internal global [1 x i8] c"\01", align 4
define i32 @load_i8(i32 %addr_arg) {
entry:
%addr = inttoptr i32 %addr_arg to i8*
%ret = load i8, i8* %addr, align 1
%ret2 = sub i8 %ret, 0
%ret_ext = zext i8 %ret2 to i32
ret i32 %ret_ext
}
; CHECK-LABEL: load_i8
; CHECK: mov {{[a-d]l}},BYTE PTR
; MIPS32-LABEL: load_i8
; MIPS32: lb
; MIPS32: addiu {{.*}},0
; MIPS32: andi {{.*}},0xff
; MIPS32: move
; MIPS32: jr
; MIPS32: nop
define i32 @load_i8_global(i32 %addr_arg) {
entry:
%addr = bitcast [1 x i8]* @global8 to i8*
%ret = load i8, i8* %addr, align 1
%ret2 = sub i8 %ret, 0
%ret_ext = zext i8 %ret2 to i32
ret i32 %ret_ext
}
; CHECK-LABEL: load_i8_global
; CHECK: mov {{[a-d]l}},{{(BYTE PTR)?}}
; MIPS32-LABEL: load_i8_global
; MIPS32: lui
; MIPS32: addiu
; MIPS32: lb
; MIPS32: addiu {{.*}},0
; MIPS32: andi {{.*}},0xff
; MIPS32: jr
; MIPS32: nop
define void @store_i8(i32 %addr_arg, i32 %val) {
entry:
%val_trunc = trunc i32 %val to i8
%addr = inttoptr i32 %addr_arg to i8*
store i8 %val_trunc, i8* %addr, align 1
ret void
}
; CHECK-LABEL: store_i8
; CHECK: mov BYTE PTR {{.*}},{{[a-d]l}}
; MIPS32-LABEL: store_i8
; MIPS32: sb
; MIPS32: jr
; MIPS32: nop
define void @store_i8_const(i32 %addr_arg) {
entry:
%addr = inttoptr i32 %addr_arg to i8*
store i8 123, i8* %addr, align 1
ret void
}
; CHECK-LABEL: store_i8_const
; CHECK: mov BYTE PTR {{.*}},0x7b
; MIPS32-LABEL: store_i8_const
; MIPS32: li
; MIPS32: sb
; MIPS32: jr
; MIPS32: nop