1; Test of multiple indirect calls to the same target. Each call 2; should be to the same operand, whether it's in a register or on the 3; stack. 4 5; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \ 6; RUN: --target x8632 -i %s --args -O2 \ 7; RUN: | %if --need=target_X8632 --command FileCheck %s 8; RUN: %if --need=allow_dump --need=target_X8632 --command %p2i --filetype=asm \ 9; RUN: --assemble --disassemble -i %s --args -O2 \ 10; RUN: | %if --need=allow_dump --need=target_X8632 --command FileCheck %s 11; RUN: %if --need=target_X8632 --command %p2i --filetype=obj --disassemble \ 12; RUN: --target x8632 -i %s --args -Om1 \ 13; RUN: | %if --need=target_X8632 --command FileCheck --check-prefix=OPTM1 %s 14 15; RUN: %if --need=target_X8664 --command %p2i --filetype=obj --disassemble \ 16; RUN: --target x8664 -i %s --args -O2 \ 17; RUN: | %if --need=target_X8664 --command FileCheck --check-prefix X8664 %s 18; RUN: %if --need=allow_dump --need=target_X8664 --command %p2i --filetype=asm \ 19; RUN: --assemble --disassemble --target x8664 -i %s --args -O2 \ 20; RUN: | %if --need=allow_dump --need=target_X8664 \ 21; RUN: --command FileCheck --check-prefix=X8664 %s 22; RUN: %if --need=target_X8664 --command %p2i --filetype=obj --disassemble \ 23; RUN: --target x8664 -i %s --args -Om1 \ 24; RUN: | %if --need=target_X8664 \ 25; RUN: --command FileCheck --check-prefix=X8664-OPTM1 %s 26 27; RUN: %if --need=target_ARM32 \ 28; RUN: --command %p2i --filetype=obj \ 29; RUN: --disassemble --target arm32 -i %s --args -O2 \ 30; RUN: | %if --need=target_ARM32 \ 31; RUN: --command FileCheck --check-prefix ARM32 %s 32; RUN: %if --need=target_ARM32 \ 33; RUN: --command %p2i --filetype=obj \ 34; RUN: --disassemble --target arm32 -i %s --args -Om1 \ 35; RUN: | %if --need=target_ARM32_dump \ 36; RUN: --command FileCheck --check-prefix ARM32 %s 37 38; RUN: %if --need=target_MIPS32 --need=allow_dump \ 39; RUN: --command %p2i --filetype=asm --assemble --disassemble --target \ 40; RUN: mips32 -i %s --args -O2 -allow-externally-defined-symbols \ 41; RUN: | %if --need=target_MIPS32 --need=allow_dump \ 42; RUN: --command FileCheck --check-prefix MIPS32 %s 43 44@__init_array_start = internal constant [0 x i8] zeroinitializer, align 4 45@__fini_array_start = internal constant [0 x i8] zeroinitializer, align 4 46@__tls_template_start = internal constant [0 x i8] zeroinitializer, align 8 47@__tls_template_alignment = internal constant [4 x i8] c"\01\00\00\00", align 4 48 49define internal void @CallIndirect(i32 %f) { 50entry: 51 %__1 = inttoptr i32 %f to void ()* 52 call void %__1() 53 call void %__1() 54 call void %__1() 55 call void %__1() 56 call void %__1() 57 call void %__1() 58 ret void 59} 60; CHECK-LABEL: CallIndirect 61; Use the first call as a barrier in case the register allocator decides to use 62; a scratch register for it but a common preserved register for the rest. 63; CHECK: call 64; CHECK: call [[REGISTER:[a-z]+]] 65; CHECK: call [[REGISTER]] 66; CHECK: call [[REGISTER]] 67; CHECK: call [[REGISTER]] 68; CHECK: call [[REGISTER]] 69; 70; OPTM1-LABEL: CallIndirect 71; OPTM1: call [[TARGET:.+]] 72; OPTM1: call [[TARGET]] 73; OPTM1: call [[TARGET]] 74; OPTM1: call [[TARGET]] 75; OPTM1: call [[TARGET]] 76; 77; X8664-LABEL: CallIndirect 78; Use the first call as a barrier so we skip the movs in the function prolog. 79; X8664: call r{{..}} 80; X8664: mov e[[REG:..]], 81; X8664-NEXT: call r[[REG]] 82; X8664: mov e[[REG:..]], 83; X8664-NEXT: call r[[REG]] 84; X8664: mov e[[REG:..]], 85; X8664-NEXT: call r[[REG]] 86; X8664: call r{{..}} 87; 88; X8664-OPTM1-LABEL: CallIndirect 89; X8664-OPTM1: mov e[[REG:..]],DWORD PTR 90; X8664-OPTM1: call r[[REG]] 91; X8664-OPTM1: mov e[[REG:..]],DWORD PTR 92; X8664-OPTM1: call r[[REG]] 93; X8664-OPTM1: mov e[[REG:..]],DWORD PTR 94; X8664-OPTM1: call r[[REG]] 95; X8664-OPTM1: mov e[[REG:..]],DWORD PTR 96; X8664-OPTM1: call r[[REG]] 97; X8664-OPTM1: mov e[[REG:..]],DWORD PTR 98; X8664-OPTM1: call r[[REG]] 99; 100; ARM32-LABEL: CallIndirect 101; ARM32: blx [[REGISTER:r.*]] 102; ARM32: blx [[REGISTER]] 103; ARM32: blx [[REGISTER]] 104; ARM32: blx [[REGISTER]] 105; ARM32: blx [[REGISTER]] 106 107; MIPS32-LABEL: CallIndirect 108; MIPS32: jalr [[REGISTER:.*]] 109; MIPS32: jalr [[REGISTER]] 110; MIPS32: jalr [[REGISTER]] 111; MIPS32: jalr [[REGISTER]] 112 113@fp_v = internal global [4 x i8] zeroinitializer, align 4 114 115define internal void @CallIndirectGlobal() { 116entry: 117 %fp_ptr_i32 = bitcast [4 x i8]* @fp_v to i32* 118 %fp_ptr = load i32, i32* %fp_ptr_i32, align 1 119 %fp = inttoptr i32 %fp_ptr to void ()* 120 call void %fp() 121 call void %fp() 122 call void %fp() 123 call void %fp() 124 ret void 125} 126; CHECK-LABEL: CallIndirectGlobal 127; Allow the first call to be to a different register because of simple 128; availability optimization. 129; CHECK: call 130; CHECK: call [[REGISTER:[a-z]+]] 131; CHECK: call [[REGISTER]] 132; CHECK: call [[REGISTER]] 133; 134; OPTM1-LABEL: CallIndirectGlobal 135; OPTM1: call [[TARGET:.+]] 136; OPTM1: call [[TARGET]] 137; OPTM1: call [[TARGET]] 138; OPTM1: call [[TARGET]] 139; 140; X8664-LABEL: CallIndirectGlobal 141; X8664: call r[[REG]] 142; X8664: mov e[[REG:..]] 143; X8664-NEXT: call r[[REG]] 144; X8664: mov e[[REG:..]] 145; X8664-NEXT: call r[[REG]] 146; X8664: call r{{..}} 147; 148; X8664-OPTM1-LABEL: CallIndirectGlobal 149; X8664-OPTM1: mov e[[REG:..]],DWORD PTR 150; X8664-OPTM1: call r[[REG]] 151; X8664-OPTM1: mov e[[REG:..]],DWORD PTR 152; X8664-OPTM1: call r[[REG]] 153; X8664-OPTM1: mov e[[REG:..]],DWORD PTR 154; X8664-OPTM1: call r[[REG]] 155; X8664-OPTM1: mov e[[REG:..]],DWORD PTR 156; X8664-OPTM1: call r[[REG]] 157; 158; ARM32-LABEL: CallIndirectGlobal 159; ARM32: blx {{r.*}} 160; ARM32: blx [[REGISTER:r[0-9]*]] 161; ARM32: blx [[REGISTER]] 162; ARM32: blx [[REGISTER]] 163 164; MIPS32-LABEL: CallIndirectGlobal 165; MIPS32: jalr [[REGISTER:.*]] 166; MIPS32: jalr [[REGISTER]] 167; MIPS32: jalr [[REGISTER]] 168; MIPS32: jalr [[REGISTER]] 169 170; Calling an absolute address is used for non-IRT PNaCl pexes to directly 171; access syscall trampolines. This is not really an indirect call, but 172; there is a cast from int to pointer first. 173define internal void @CallConst() { 174entry: 175 %__1 = inttoptr i32 66496 to void ()* 176 call void %__1() 177 call void %__1() 178 call void %__1() 179 ret void 180} 181 182; CHECK-LABEL: CallConst 183; CHECK: e8 bc 03 01 00 call {{[0-9a-f]+}} {{.*}} R_386_PC32 *ABS* 184; CHECK: e8 bc 03 01 00 call {{[0-9a-f]+}} {{.*}} R_386_PC32 *ABS* 185; CHECK: e8 bc 03 01 00 call {{[0-9a-f]+}} {{.*}} R_386_PC32 *ABS* 186; 187; OPTM1-LABEL: CallConst 188; OPTM1: e8 bc 03 01 00 call {{[0-9a-f]+}} {{.*}} R_386_PC32 *ABS* 189; OPTM1: e8 bc 03 01 00 call {{[0-9a-f]+}} {{.*}} R_386_PC32 *ABS* 190; OPTM1: e8 bc 03 01 00 call {{[0-9a-f]+}} {{.*}} R_386_PC32 *ABS* 191; 192; X8664-LABEL: CallConst 193; TODO(jpp): fix absolute call emission. 194; These are broken: the emitted code should be 195; e8 00 00 00 00 call {{.*}} *ABS*+0x103bc 196; 197; X8664-OPTM1-LABEL: CallConst 198; TODO(jpp): fix absolute call emission. 199; These are broken: the emitted code should be 200; e8 00 00 00 00 call {{.*}} *ABS*+0x103bc 201; 202; ARM32-LABEL: CallConst 203; ARM32: movw [[REGISTER:r.*]], #960 204; ARM32: movt [[REGISTER]], #1 205; ARM32: blx [[REGISTER]] 206; The legalization of the constant could be shared, but it isn't. 207; ARM32: movw [[REGISTER:r.*]], #960 208; ARM32: blx [[REGISTER]] 209; ARM32: blx [[REGISTER]] 210