|  | ; This is a test of C-level conversion operations that clang lowers | 
|  | ; into pairs of shifts. | 
|  |  | 
|  | ; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \ | 
|  | ; RUN:   --target x8632 -i %s --args -O2 \ | 
|  | ; RUN:   | %if --need=target_X8632 --command FileCheck %s | 
|  |  | 
|  | ; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \ | 
|  | ; RUN:   --target x8632 -i %s --args -Om1 \ | 
|  | ; RUN:   | %if --need=target_X8632 --command FileCheck %s | 
|  |  | 
|  | ; RUN: %if --need=target_ARM32 \ | 
|  | ; RUN:   --command %p2i --filetype=obj \ | 
|  | ; RUN:   --disassemble --target arm32 -i %s --args -O2 \ | 
|  | ; RUN:   | %if --need=target_ARM32 \ | 
|  | ; RUN:   --command FileCheck --check-prefix ARM32 %s | 
|  |  | 
|  | ; RUN: %if --need=target_ARM32 \ | 
|  | ; RUN:   --command %p2i --filetype=obj \ | 
|  | ; RUN:   --disassemble --target arm32 -i %s --args -Om1 \ | 
|  | ; RUN:   | %if --need=target_ARM32 \ | 
|  | ; RUN:   --command FileCheck --check-prefix ARM32 %s | 
|  |  | 
|  | ; RUN: %if --need=target_MIPS32 --need=allow_dump \ | 
|  | ; RUN:   --command %p2i --filetype=asm --assemble \ | 
|  | ; RUN:   --disassemble --target mips32 -i %s --args -O2 \ | 
|  | ; RUN:   | %if --need=target_MIPS32 --need=allow_dump \ | 
|  | ; RUN:   --command FileCheck --check-prefix MIPS32-O2 --check-prefix MIPS32 %s | 
|  |  | 
|  | ; RUN: %if --need=target_MIPS32 --need=allow_dump \ | 
|  | ; RUN:   --command %p2i --filetype=asm --assemble \ | 
|  | ; RUN:   --disassemble --target mips32 -i %s --args -Om1 \ | 
|  | ; RUN:   | %if --need=target_MIPS32 --need=allow_dump \ | 
|  | ; RUN:   --command FileCheck --check-prefix MIPS32-OM1 --check-prefix MIPS32 %s | 
|  |  | 
|  | @i1 = internal global [4 x i8] zeroinitializer, align 4 | 
|  | @i2 = internal global [4 x i8] zeroinitializer, align 4 | 
|  | @u1 = internal global [4 x i8] zeroinitializer, align 4 | 
|  |  | 
|  | define internal void @conv1() { | 
|  | entry: | 
|  | %__0 = bitcast [4 x i8]* @u1 to i32* | 
|  | %v0 = load i32, i32* %__0, align 1 | 
|  | %sext = shl i32 %v0, 24 | 
|  | %v1 = ashr i32 %sext, 24 | 
|  | %__4 = bitcast [4 x i8]* @i1 to i32* | 
|  | store i32 %v1, i32* %__4, align 1 | 
|  | ret void | 
|  | } | 
|  | ; CHECK-LABEL: conv1 | 
|  | ; CHECK: shl {{.*}},0x18 | 
|  | ; CHECK: sar {{.*}},0x18 | 
|  |  | 
|  | ; ARM32-LABEL: conv1 | 
|  | ; ARM32: lsl {{.*}}, #24 | 
|  | ; ARM32: asr {{.*}}, #24 | 
|  |  | 
|  | define internal void @conv2() { | 
|  | entry: | 
|  | %__0 = bitcast [4 x i8]* @u1 to i32* | 
|  | %v0 = load i32, i32* %__0, align 1 | 
|  | %sext1 = shl i32 %v0, 16 | 
|  | %v1 = lshr i32 %sext1, 16 | 
|  | %__4 = bitcast [4 x i8]* @i2 to i32* | 
|  | store i32 %v1, i32* %__4, align 1 | 
|  | ret void | 
|  | } | 
|  | ; CHECK-LABEL: conv2 | 
|  | ; CHECK: shl {{.*}},0x10 | 
|  | ; CHECK: shr {{.*}},0x10 | 
|  |  | 
|  | ; ARM32-LABEL: conv2 | 
|  | ; ARM32: lsl {{.*}}, #16 | 
|  | ; ARM32: lsr {{.*}}, #16 | 
|  |  | 
|  | define internal i32 @shlImmLarge(i32 %val) { | 
|  | entry: | 
|  | %result = shl i32 %val, 257 | 
|  | ret i32 %result | 
|  | } | 
|  | ; CHECK-LABEL: shlImmLarge | 
|  | ; CHECK: shl {{.*}},0x1 | 
|  |  | 
|  | ; MIPS32-LABEL: shlImmLarge | 
|  | ; MIPS32: sll | 
|  |  | 
|  | define internal i32 @shlImmNeg(i32 %val) { | 
|  | entry: | 
|  | %result = shl i32 %val, -1 | 
|  | ret i32 %result | 
|  | } | 
|  | ; CHECK-LABEL: shlImmNeg | 
|  | ; CHECK: shl {{.*}},0xff | 
|  |  | 
|  | ; MIPS32-LABEL: shlImmNeg | 
|  | ; MIPS32: sll | 
|  |  | 
|  | define internal i32 @lshrImmLarge(i32 %val) { | 
|  | entry: | 
|  | %result = lshr i32 %val, 257 | 
|  | ret i32 %result | 
|  | } | 
|  | ; CHECK-LABEL: lshrImmLarge | 
|  | ; CHECK: shr {{.*}},0x1 | 
|  |  | 
|  | ; MIPS32-LABEL: lshrImmLarge | 
|  | ; MIPS32: srl | 
|  |  | 
|  | define internal i32 @lshrImmNeg(i32 %val) { | 
|  | entry: | 
|  | %result = lshr i32 %val, -1 | 
|  | ret i32 %result | 
|  | } | 
|  | ; CHECK-LABEL: lshrImmNeg | 
|  | ; CHECK: shr {{.*}},0xff | 
|  |  | 
|  | ; MIPS32-LABEL: lshrImmNeg | 
|  | ; MIPS32: srl | 
|  |  | 
|  | define internal i32 @ashrImmLarge(i32 %val) { | 
|  | entry: | 
|  | %result = ashr i32 %val, 257 | 
|  | ret i32 %result | 
|  | } | 
|  | ; CHECK-LABEL: ashrImmLarge | 
|  | ; CHECK: sar {{.*}},0x1 | 
|  |  | 
|  | ; MIPS32-LABEL: ashrImmLarge | 
|  | ; MIPS32: sra | 
|  |  | 
|  | define internal i32 @ashrImmNeg(i32 %val) { | 
|  | entry: | 
|  | %result = ashr i32 %val, -1 | 
|  | ret i32 %result | 
|  | } | 
|  | ; CHECK-LABEL: ashrImmNeg | 
|  | ; CHECK: sar {{.*}},0xff | 
|  |  | 
|  | ; MIPS32-LABEL: ashrImmNeg | 
|  | ; MIPS32: sra | 
|  |  | 
|  | define internal i64 @shlImm64One(i64 %val) { | 
|  | entry: | 
|  | %result = shl i64 %val, 1 | 
|  | ret i64 %result | 
|  | } | 
|  | ; CHECK-LABEL: shlImm64One | 
|  | ; CHECK: shl {{.*}},1 | 
|  | ; MIPS32-LABEL: shlImm64One | 
|  | ; MIPS32: addu	[[T_LO:.*]],[[VAL_LO:.*]],[[VAL_LO]] | 
|  | ; MIPS32: sltu	[[T1:.*]],[[T_LO]],[[VAL_LO]] | 
|  | ; MIPS32: addu	[[T2:.*]],[[T1]],[[VAL_HI:.*]] | 
|  | ; MIPS32: addu	{{.*}},[[VAL_HI]],[[T2]] | 
|  |  | 
|  | define internal i64 @shlImm64LessThan32(i64 %val) { | 
|  | entry: | 
|  | %result = shl i64 %val, 4 | 
|  | ret i64 %result | 
|  | } | 
|  | ; CHECK-LABEL: shlImm64LessThan32 | 
|  | ; CHECK: shl {{.*}},0x4 | 
|  | ; MIPS32-LABEL: shlImm64LessThan32 | 
|  | ; MIPS32: srl	[[T1:.*]],[[VAL_LO:.*]],0x1c | 
|  | ; MIPS32: sll	[[T2:.*]],{{.*}},0x4 | 
|  | ; MIPS32: or	{{.*}},[[T1]],[[T2]] | 
|  | ; MIPS32: sll	{{.*}},[[VAL_LO]],0x4 | 
|  |  | 
|  | define internal i64 @shlImm64Equal32(i64 %val) { | 
|  | entry: | 
|  | %result = shl i64 %val, 32 | 
|  | ret i64 %result | 
|  | } | 
|  | ; CHECK-LABEL: shlImm64Equal32 | 
|  | ; CHECK-NOT: shl | 
|  | ; MIPS32-LABEL: shlImm64Equal32 | 
|  | ; MIPS32: li	{{.*}},0 | 
|  | ; MIPS32-O2:	move | 
|  | ; MIPS32-OM1:	sw | 
|  | ; MIPS32-OM1:	lw | 
|  |  | 
|  | define internal i64 @shlImm64GreaterThan32(i64 %val) { | 
|  | entry: | 
|  | %result = shl i64 %val, 40 | 
|  | ret i64 %result | 
|  | } | 
|  | ; CHECK-LABEL: shlImm64GreaterThan32 | 
|  | ; CHECK: shl {{.*}},0x8 | 
|  | ; MIPS32-LABEL: shlImm64GreaterThan32 | 
|  | ; MIPS32: sll	{{.*}},{{.*}},0x8 | 
|  | ; MIPS32: li	{{.*}},0 | 
|  |  | 
|  | define internal i64 @lshrImm64One(i64 %val) { | 
|  | entry: | 
|  | %result = lshr i64 %val, 1 | 
|  | ret i64 %result | 
|  | } | 
|  | ; CHECK-LABEL: lshrImm64One | 
|  | ; CHECK: shr {{.*}},1 | 
|  | ; MIPS32-LABEL: lshrImm64One | 
|  | ; MIPS32: sll	[[T1:.*]],[[VAL_HI:.*]],0x1f | 
|  | ; MIPS32: srl	[[T2:.*]],{{.*}},0x1 | 
|  | ; MIPS32: or	{{.*}},[[T1]],[[T2]] | 
|  | ; MIPS32: srl	{{.*}},[[VAL_HI]],0x1 | 
|  |  | 
|  | define internal i64 @lshrImm64LessThan32(i64 %val) { | 
|  | entry: | 
|  | %result = lshr i64 %val, 4 | 
|  | ret i64 %result | 
|  | } | 
|  | ; CHECK-LABEL: lshrImm64LessThan32 | 
|  | ; CHECK: shrd {{.*}},0x4 | 
|  | ; CHECK: shr {{.*}},0x4 | 
|  | ; MIPS32-LABEL: lshrImm64LessThan32 | 
|  | ; MIPS32: sll	[[T1:.*]],[[VAL_HI:.*]],0x1c | 
|  | ; MIPS32: srl	[[T2:.*]],{{.*}},0x4 | 
|  | ; MIPS32: or	{{.*}},[[T1]],[[T2]] | 
|  | ; MIPS32: srl	{{.*}},[[VAL_HI]],0x4 | 
|  |  | 
|  | define internal i64 @lshrImm64Equal32(i64 %val) { | 
|  | entry: | 
|  | %result = lshr i64 %val, 32 | 
|  | ret i64 %result | 
|  | } | 
|  | ; CHECK-LABEL: lshrImm64Equal32 | 
|  | ; CHECK-NOT: shr | 
|  | ; MIPS32-LABEL: lshrImm64Equal32 | 
|  | ; MIPS32: li	{{.*}},0 | 
|  | ; MIPS32-O2: move | 
|  | ; MIPS32-OM1: sw | 
|  | ; MIPS32-OM1: lw | 
|  |  | 
|  | define internal i64 @lshrImm64GreaterThan32(i64 %val) { | 
|  | entry: | 
|  | %result = lshr i64 %val, 40 | 
|  | ret i64 %result | 
|  | } | 
|  | ; CHECK-LABEL: lshrImm64GreaterThan32 | 
|  | ; CHECK-NOT: shrd | 
|  | ; CHECK: shr {{.*}},0x8 | 
|  | ; MIPS32-LABEL: lshrImm64GreaterThan32 | 
|  | ; MIPS32: srl	{{.*}},{{.*}},0x8 | 
|  | ; MIPS32: li	{{.*}},0 | 
|  |  | 
|  | define internal i64 @ashrImm64One(i64 %val) { | 
|  | entry: | 
|  | %result = ashr i64 %val, 1 | 
|  | ret i64 %result | 
|  | } | 
|  | ; CHECK-LABEL: ashrImm64One | 
|  | ; CHECK: shrd {{.*}},0x1 | 
|  | ; CHECK: sar {{.*}},1 | 
|  | ; MIPS32-LABEL: ashrImm64One | 
|  | ; MIPS32: sll	[[T1:.*]],[[VAL_HI:.*]],0x1f | 
|  | ; MIPS32: srl	[[T2:.*]],{{.*}},0x1 | 
|  | ; MIPS32: or	{{.*}},[[T1]],[[T2]] | 
|  | ; MIPS32: sra	{{.*}},[[VAL_HI]],0x1 | 
|  |  | 
|  | define internal i64 @ashrImm64LessThan32(i64 %val) { | 
|  | entry: | 
|  | %result = ashr i64 %val, 4 | 
|  | ret i64 %result | 
|  | } | 
|  | ; CHECK-LABEL: ashrImm64LessThan32 | 
|  | ; CHECK: shrd {{.*}},0x4 | 
|  | ; CHECK: sar {{.*}},0x4 | 
|  | ; MIPS32-LABEL: ashrImm64LessThan32 | 
|  | ; MIPS32: sll   [[T1:.*]],[[VAL_HI:.*]],0x1c | 
|  | ; MIPS32: srl   [[T2:.*]],{{.*}},0x4 | 
|  | ; MIPS32: or    {{.*}},[[T1]],[[T2]] | 
|  | ; MIPS32: sra   {{.*}},[[VAL_HI]],0x4 | 
|  |  | 
|  | define internal i64 @ashrImm64Equal32(i64 %val) { | 
|  | entry: | 
|  | %result = ashr i64 %val, 32 | 
|  | ret i64 %result | 
|  | } | 
|  | ; CHECK-LABEL: ashrImm64Equal32 | 
|  | ; CHECK: sar {{.*}},0x1f | 
|  | ; CHECK-NOT: shrd | 
|  | ; MIPS32-LABEL: ashrImm64Equal32 | 
|  | ; MIPS32: sra	{{.*}},[[VAL_HI:.*]],0x1f | 
|  | ; MIPS32-O2: move	{{.*}},[[VAL_HI]] | 
|  | ; MIPS32-OM1:	sw [[VAL_HI]],{{.*}} | 
|  | ; MIPS32-OM1:   lw {{.*}},{{.*}} | 
|  |  | 
|  | define internal i64 @ashrImm64GreaterThan32(i64 %val) { | 
|  | entry: | 
|  | %result = ashr i64 %val, 40 | 
|  | ret i64 %result | 
|  | } | 
|  | ; CHECK-LABEL: ashrImm64GreaterThan32 | 
|  | ; CHECK: sar {{.*}},0x1f | 
|  | ; CHECK: shrd {{.*}},0x8 | 
|  | ; MIPS32-LABEL: ashrImm64GreaterThan32 | 
|  | ; MIPS32: sra	{{.*}},[[VAL_HI:.*]],0x8 | 
|  | ; MIPS32: sra	{{.*}},[[VAL_HI]],0x1f |