// Attach attributes to inalloca argument.
if (IRFunctionArgs.hasInallocaArg()) {
llvm::AttrBuilder Attrs;
- Attrs.addAttribute(llvm::Attribute::InAlloca);
+ Attrs.addInAllocaAttr(FI.getArgStruct());
ArgAttrs[IRFunctionArgs.getInallocaArgNo()] =
llvm::AttributeSet::get(getLLVMContext(), Attrs);
}
bar(f);
}
-// WINDOWS: define dso_local i32 @"?bar@@YAHUFoo@@@Z"(<{ %struct.Foo }>* inalloca %0)
+// WINDOWS: define dso_local i32 @"?bar@@YAHUFoo@@@Z"(<{ %struct.Foo }>* inalloca(<{ %struct.Foo }>) %0)
// WINDOWS: %[[O:[0-9a-zA-Z]+]] = getelementptr inbounds <{ %struct.Foo }>, <{ %struct.Foo }>* %0, i32 0, i32 0
// WINDOWS: %[[X:[0-9a-zA-Z]+]] = getelementptr inbounds %struct.Foo, %struct.Foo* %[[O]], i32 0, i32 0
// WINDOWS: %[[LOAD:[0-9a-zA-Z]+]] = load i32, i32* %[[X]]
// WINDOWS: ret i32 %[[LOAD]]
-// WINDOWS: define dso_local i32 @"?bar@@YAHUFoo@@@Z.sse4.2"(<{ %struct.Foo }>* inalloca %0)
+// WINDOWS: define dso_local i32 @"?bar@@YAHUFoo@@@Z.sse4.2"(<{ %struct.Foo }>* inalloca(<{ %struct.Foo }>) %0)
// WINDOWS: %[[O:[0-9a-zA-Z]+]] = getelementptr inbounds <{ %struct.Foo }>, <{ %struct.Foo }>* %0, i32 0, i32 0
// WINDOWS: %[[X:[0-9a-zA-Z]+]] = getelementptr inbounds %struct.Foo, %struct.Foo* %[[O]], i32 0, i32 0
// WINDOWS: %[[LOAD:[0-9a-zA-Z]+]] = load i32, i32* %[[X]]
// WINDOWS: %[[ADD:[0-9a-zA-Z]+]] = add nsw i32 %[[LOAD]], 1
// WINDOWS: ret i32 %[[ADD]]
-// WINDOWS: define dso_local i32 @"?bar@@YAHUFoo@@@Z.arch_ivybridge"(<{ %struct.Foo }>* inalloca %0)
+// WINDOWS: define dso_local i32 @"?bar@@YAHUFoo@@@Z.arch_ivybridge"(<{ %struct.Foo }>* inalloca(<{ %struct.Foo }>) %0)
// WINDOWS: %[[O:[0-9a-zA-Z]+]] = getelementptr inbounds <{ %struct.Foo }>, <{ %struct.Foo }>* %0, i32 0, i32 0
// WINDOWS: %[[X:[0-9a-zA-Z]+]] = getelementptr inbounds %struct.Foo, %struct.Foo* %[[O]], i32 0, i32 0
// WINDOWS: %[[LOAD:[0-9a-zA-Z]+]] = load i32, i32* %[[X]]
// WINDOWS: define dso_local void @"?usage@@YAXXZ"()
// WINDOWS: %[[F:[0-9a-zA-Z]+]] = alloca %struct.Foo
// WINDOWS: %[[ARGMEM:[0-9a-zA-Z]+]] = alloca inalloca <{ %struct.Foo }>
-// WINDOWS: %[[CALL:[0-9a-zA-Z]+]] = call i32 @"?bar@@YAHUFoo@@@Z.resolver"(<{ %struct.Foo }>* inalloca %[[ARGMEM]])
+// WINDOWS: %[[CALL:[0-9a-zA-Z]+]] = call i32 @"?bar@@YAHUFoo@@@Z.resolver"(<{ %struct.Foo }>* inalloca(<{ %struct.Foo }>) %[[ARGMEM]])
// WINDOWS: define weak_odr dso_local i32 @"?bar@@YAHUFoo@@@Z.resolver"(<{ %struct.Foo }>* %0)
// WINDOWS: %[[RET:[0-9a-zA-Z]+]] = musttail call i32 @"?bar@@YAHUFoo@@@Z.arch_ivybridge"(<{ %struct.Foo }>* %0)
}
// CHECK-LABEL: define dso_local i32 @"?receive_inalloca_overaligned@@Y{{.*}}"
-// CHECK-SAME: (<{ %struct.NonTrivial, %struct.OverAligned* }>* inalloca %0)
+// CHECK-SAME: (<{ %struct.NonTrivial, %struct.OverAligned* }>* inalloca(<{ %struct.NonTrivial, %struct.OverAligned* }>) %0)
int pass_inalloca_overaligned() {
gvi32 = receive_inalloca_overaligned(NonTrivial(), OverAligned());
// Store the address of an OverAligned temporary into the struct.
// CHECK: getelementptr inbounds <{ %struct.NonTrivial, %struct.OverAligned* }>, <{ %struct.NonTrivial, %struct.OverAligned* }>* %{{.*}}, i32 0, i32 1
// CHECK: store %struct.OverAligned* [[TMP]], %struct.OverAligned** %{{.*}}, align 4
-// CHECK: call i32 @"?receive_inalloca_overaligned@@Y{{.*}}"(<{ %struct.NonTrivial, %struct.OverAligned* }>* inalloca %argmem)
+// CHECK: call i32 @"?receive_inalloca_overaligned@@Y{{.*}}"(<{ %struct.NonTrivial, %struct.OverAligned* }>* inalloca(<{ %struct.NonTrivial, %struct.OverAligned* }>) %argmem)
int receive_both(Both o) {
return o.x + o.y;
}
// CHECK-LABEL: define dso_local i32 @"?receive_inalloca_both@@Y{{.*}}"
-// CHECK-SAME: (<{ %struct.NonTrivial, %struct.Both* }>* inalloca %0)
+// CHECK-SAME: (<{ %struct.NonTrivial, %struct.Both* }>* inalloca(<{ %struct.NonTrivial, %struct.Both* }>) %0)
int pass_inalloca_both() {
gvi32 = receive_inalloca_both(NonTrivial(), Both());
// CHECK-LABEL: define dso_local i32 @"?pass_inalloca_both@@Y{{.*}}"
// CHECK: [[TMP:%[^ ]*]] = alloca %struct.Both, align 8
// CHECK: call x86_thiscallcc %struct.Both* @"??0Both@@QAE@XZ"(%struct.Both* {{[^,]*}} [[TMP]])
-// CHECK: call i32 @"?receive_inalloca_both@@Y{{.*}}"(<{ %struct.NonTrivial, %struct.Both* }>* inalloca %argmem)
+// CHECK: call i32 @"?receive_inalloca_both@@Y{{.*}}"(<{ %struct.NonTrivial, %struct.Both* }>* inalloca(<{ %struct.NonTrivial, %struct.Both* }>) %argmem)
// Here we have a type that is:
// - overaligned
// CHECK: call zeroext i1 @"?cond@@YA_NXZ"()
// CHECK: br i1
// CHECK: br label %out
-// CHECK: call void @"?inalloca@@YAXUFoo@@0@Z"(<{ %struct.Foo, %struct.Foo }>* inalloca %{{.*}})
+// CHECK: call void @"?inalloca@@YAXUFoo@@0@Z"(<{ %struct.Foo, %struct.Foo }>* inalloca(<{ %struct.Foo, %struct.Foo }>) %{{.*}})
// CHECK: call void @llvm.stackrestore(i8* %inalloca.save)
// CHECK: out:
// CHECK-SAME: (<4 x float> inreg %x,
// CHECK-SAME: <4 x float> inreg %y,
// CHECK-SAME: <4 x float> inreg %z,
-// CHECK-SAME: <{ %struct.NonTrivial, <4 x float>*, <4 x float>* }>* inalloca %0)
+// CHECK-SAME: <{ %struct.NonTrivial, <4 x float>*, <4 x float>* }>* inalloca(<{ %struct.NonTrivial, <4 x float>*, <4 x float>* }>) %0)
void pass_vec_128() {
__m128 z = {0};
// CHECK-SAME: (<4 x float> inreg %{{[^,]*}},
// CHECK-SAME: <4 x float> inreg %{{[^,]*}},
// CHECK-SAME: <4 x float> inreg %{{[^,]*}},
-// CHECK-SAME: <{ %struct.NonTrivial, <4 x float>*, <4 x float>* }>* inalloca %{{[^,]*}})
+// CHECK-SAME: <{ %struct.NonTrivial, <4 x float>*, <4 x float>* }>* inalloca(<{ %struct.NonTrivial, <4 x float>*, <4 x float>* }>) %{{[^,]*}})
// w will be passed indirectly by register, and q will be passed indirectly, but
// the pointer will be in memory.
// CHECK-SAME: <4 x float> inreg %z,
// CHECK-SAME: <4 x float>* inreg %0,
// CHECK-SAME: i32 inreg %edx,
-// CHECK-SAME: <{ <4 x float>*, %struct.NonTrivial }>* inalloca %1)
+// CHECK-SAME: <{ <4 x float>*, %struct.NonTrivial }>* inalloca(<{ <4 x float>*, %struct.NonTrivial }>) %1)
void __vectorcall vectorcall_receive_vec(double xmm0, double xmm1, double xmm2,
// CHECK-SAME: <4 x float> inreg %z,
// CHECK-SAME: <4 x float>* inreg %0,
// CHECK-SAME: i32 inreg %edx,
-// CHECK-SAME: <{ <4 x float>*, %struct.NonTrivial }>* inalloca %1)
+// CHECK-SAME: <{ <4 x float>*, %struct.NonTrivial }>* inalloca(<{ <4 x float>*, %struct.NonTrivial }>) %1)
// WIN32: store i32 2, i32* %[[ARG2]]
// WIN32: %[[ARG4:.*]] = getelementptr {{.*}} %[[ARGMEM]]
// WIN32: store {{.*}}* %[[TMP]], {{.*}}** %[[ARG4]]
- // WIN32: call {{.*}} @"??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]])
+ // WIN32: call {{.*}} @"??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca(<{{.*}}>) %[[ARGMEM]])
// WIN32: call void @llvm.stackrestore(
// WIN32: call {{.*}} @"??0Z@@QAE@XZ"(
// WIN32: call {{.*}} @"??1Q@@QAE@XZ"(
// WIN32: store i32 2, i32* %[[ARG2]]
// WIN32: %[[ARG4:.*]] = getelementptr {{.*}} %[[ARGMEM]]
// WIN32: store {{.*}}* %[[TMP]], {{.*}}** %[[ARG4]]
- // WIN32: call {{.*}} @"??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]])
+ // WIN32: call {{.*}} @"??0A@inalloca_nonvirt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca(<{{.*}}>) %[[ARGMEM]])
// WIN32: call void @llvm.stackrestore(
// WIN32: call {{.*}} @"??0Z@@QAE@XZ"(
// WIN32: call {{.*}} @"??1Q@@QAE@XZ"(
// WIN32: store i32 2, i32* %[[ARG2]]
// WIN32: %[[ARG4:.*]] = getelementptr {{.*}} %[[ARGMEM]]
// WIN32: store {{.*}}* %[[TMP]], {{.*}}** %[[ARG4]]
- // WIN32: call {{.*}} @"??0A@inalloca_virt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]])
+ // WIN32: call {{.*}} @"??0A@inalloca_virt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca(<{{.*}}>) %[[ARGMEM]])
// WIN32: call void @llvm.stackrestore(
// WIN32: br
//
// WIN32: store i32 2, i32* %[[ARG2]]
// WIN32: %[[ARG4:.*]] = getelementptr {{.*}} %[[ARGMEM]]
// WIN32: store {{.*}}* %[[TMP]], {{.*}}** %[[ARG4]]
- // WIN32: call {{.*}} @"??0A@inalloca_virt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca %[[ARGMEM]])
+ // WIN32: call {{.*}} @"??0A@inalloca_virt@@QAE@UQ@@H0$$QAU2@@Z"(%{{[^,]*}}, <{{.*}}>* inalloca(<{{.*}}>) %[[ARGMEM]])
// WIN32: call void @llvm.stackrestore(
// WIN32: br
//
// Order of destruction should be left to right.
//
// X86-LABEL: define dso_local void @"?foo@@YAXUA@@00@Z"
-// X86: ([[argmem_ty:<{ %struct.A, %struct.A, %struct.A }>]]* inalloca %0)
+// X86: ([[argmem_ty:<{ %struct.A, %struct.A, %struct.A }>]]* inalloca([[argmem_ty]]) %0)
// X86: %[[a:[^ ]*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %0, i32 0, i32 0
// X86: %[[b:[^ ]*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %0, i32 0, i32 1
// X86: %[[c:[^ ]*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %0, i32 0, i32 2
// X86: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@H@Z"(%struct.A* {{[^,]*}} %[[arg2]], i32 2)
// X86: %[[arg1:[^ ]*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 0
// X86: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@H@Z"(%struct.A* {{[^,]*}} %[[arg1]], i32 1)
-// X86: call void @"?foo@@YAXUA@@00@Z"([[argmem_ty]]* inalloca %[[argmem]])
+// X86: call void @"?foo@@YAXUA@@00@Z"([[argmem_ty]]* inalloca([[argmem_ty]]) %[[argmem]])
// X86: call void @llvm.stackrestore
// X86: ret void
//
}
// CHECK-LABEL: define dso_local x86_thiscallcc %struct.A* @"?foo@B@@QAE?AUA@@U2@@Z"
-// CHECK: (%struct.B* %this, <{ %struct.A*, %struct.A }>* inalloca %0)
+// CHECK: (%struct.B* %this, <{ %struct.A*, %struct.A }>* inalloca(<{ %struct.A*, %struct.A }>) %0)
// CHECK: getelementptr inbounds <{ %struct.A*, %struct.A }>, <{ %struct.A*, %struct.A }>* %{{.*}}, i32 0, i32 0
// CHECK: load %struct.A*, %struct.A**
// CHECK: ret %struct.A*
}
// CHECK-LABEL: define dso_local %struct.A* @"?bar@B@@QAA?AUA@@U2@@Z"
-// CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca %0)
+// CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca(<{ %struct.B*, %struct.A*, %struct.A }>) %0)
// CHECK: getelementptr inbounds <{ %struct.B*, %struct.A*, %struct.A }>, <{ %struct.B*, %struct.A*, %struct.A }>* %{{.*}}, i32 0, i32 1
// CHECK: load %struct.A*, %struct.A**
// CHECK: ret %struct.A*
}
// CHECK-LABEL: define dso_local x86_stdcallcc %struct.A* @"?baz@B@@QAG?AUA@@U2@@Z"
-// CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca %0)
+// CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca(<{ %struct.B*, %struct.A*, %struct.A }>) %0)
// CHECK: getelementptr inbounds <{ %struct.B*, %struct.A*, %struct.A }>, <{ %struct.B*, %struct.A*, %struct.A }>* %{{.*}}, i32 0, i32 1
// CHECK: load %struct.A*, %struct.A**
// CHECK: ret %struct.A*
}
// CHECK-LABEL: define dso_local x86_fastcallcc void @"?qux@B@@QAI?AUA@@U2@@Z"
-// CHECK: (%struct.B* inreg %this, %struct.A* inreg noalias sret(%struct.A) align 4 %agg.result, <{ %struct.A }>* inalloca %0)
+// CHECK: (%struct.B* inreg %this, %struct.A* inreg noalias sret(%struct.A) align 4 %agg.result, <{ %struct.A }>* inalloca(<{ %struct.A }>) %0)
// CHECK: ret void
int main() {
}
// CHECK: call x86_thiscallcc %struct.A* @"?foo@B@@QAE?AUA@@U2@@Z"
-// CHECK: (%struct.B* %{{[^,]*}}, <{ %struct.A*, %struct.A }>* inalloca %{{[^,]*}})
+// CHECK: (%struct.B* %{{[^,]*}}, <{ %struct.A*, %struct.A }>* inalloca(<{ %struct.A*, %struct.A }>) %{{[^,]*}})
// CHECK: call %struct.A* @"?bar@B@@QAA?AUA@@U2@@Z"
-// CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca %{{[^,]*}})
+// CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca(<{ %struct.B*, %struct.A*, %struct.A }>) %{{[^,]*}})
// CHECK: call x86_stdcallcc %struct.A* @"?baz@B@@QAG?AUA@@U2@@Z"
-// CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca %{{[^,]*}})
+// CHECK: (<{ %struct.B*, %struct.A*, %struct.A }>* inalloca(<{ %struct.B*, %struct.A*, %struct.A }>) %{{[^,]*}})
// CHECK: call x86_fastcallcc void @"?qux@B@@QAI?AUA@@U2@@Z"
-// CHECK: (%struct.B* inreg %{{[^,]*}}, %struct.A* inreg sret(%struct.A) align 4 %{{.*}}, <{ %struct.A }>* inalloca %{{[^,]*}})
+// CHECK: (%struct.B* inreg %{{[^,]*}}, %struct.A* inreg sret(%struct.A) align 4 %{{.*}}, <{ %struct.A }>* inalloca(<{ %struct.A }>) %{{[^,]*}})
C::C() {} // force emission
// CHECK32-LABEL: define linkonce_odr dso_local x86_thiscallcc void @"?foo@C@byval_thunk@@W3AEXUAgg@2@@Z"
-// CHECK32: (%"struct.byval_thunk::C"* %this, <{ %"struct.byval_thunk::Agg" }>* inalloca %0)
+// CHECK32: (%"struct.byval_thunk::C"* %this, <{ %"struct.byval_thunk::Agg" }>* inalloca(<{ %"struct.byval_thunk::Agg" }>) %0)
// CHECK32: getelementptr i8, i8* %{{.*}}, i32 -4
// CHECK32: musttail call x86_thiscallcc void @"?foo@C@byval_thunk@@UAEXUAgg@2@@Z"
-// CHECK32: (%"struct.byval_thunk::C"* %{{.*}}, <{ %"struct.byval_thunk::Agg" }>* inalloca %0)
+// CHECK32: (%"struct.byval_thunk::C"* %{{.*}}, <{ %"struct.byval_thunk::Agg" }>* inalloca(<{ %"struct.byval_thunk::Agg" }>) %0)
// CHECK32-NEXT: ret void
// CHECK64-LABEL: define linkonce_odr dso_local void @"?foo@C@byval_thunk@@W7EAAXUAgg@2@@Z"
C::C() {} // force emission
// CHECK32-LABEL: define linkonce_odr dso_local x86_stdcallcc void @"?foo@C@stdcall_thunk@@W3AGXUAgg@2@@Z"
-// CHECK32: (<{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>* inalloca %0)
+// CHECK32: (<{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>* inalloca(<{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>) %0)
// CHECK32: %[[this_slot:[^ ]*]] = getelementptr inbounds <{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>, <{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>* %0, i32 0, i32 0
// CHECK32: load %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::C"** %[[this_slot]]
// CHECK32: getelementptr i8, i8* %{{.*}}, i32 -4
// CHECK32: store %"struct.stdcall_thunk::C"* %{{.*}}, %"struct.stdcall_thunk::C"** %[[this_slot]]
// CHECK32: musttail call x86_stdcallcc void @"?foo@C@stdcall_thunk@@UAGXUAgg@2@@Z"
-// CHECK32: (<{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>* inalloca %0)
+// CHECK32: (<{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>* inalloca(<{ %"struct.stdcall_thunk::C"*, %"struct.stdcall_thunk::Agg" }>) %0)
// CHECK32-NEXT: ret void
// CHECK64-LABEL: define linkonce_odr dso_local void @"?foo@C@stdcall_thunk@@W7EAAXUAgg@2@@Z"
C::C() {} // force emission
// CHECK32-LABEL: define linkonce_odr dso_local %"struct.sret_thunk::Agg"* @"?foo@C@sret_thunk@@W3AA?AUAgg@2@U32@@Z"
-// CHECK32: (<{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>* inalloca %0)
+// CHECK32: (<{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>* inalloca(<{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>) %0)
// CHECK32: %[[this_slot:[^ ]*]] = getelementptr inbounds <{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>, <{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>* %0, i32 0, i32 0
// CHECK32: load %"struct.sret_thunk::C"*, %"struct.sret_thunk::C"** %[[this_slot]]
// CHECK32: getelementptr i8, i8* %{{.*}}, i32 -4
// CHECK32: store %"struct.sret_thunk::C"* %{{.*}}, %"struct.sret_thunk::C"** %[[this_slot]]
// CHECK32: %[[rv:[^ ]*]] = musttail call %"struct.sret_thunk::Agg"* @"?foo@C@sret_thunk@@UAA?AUAgg@2@U32@@Z"
-// CHECK32: (<{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>* inalloca %0)
+// CHECK32: (<{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>* inalloca(<{ %"struct.sret_thunk::C"*, %"struct.sret_thunk::Agg"*, %"struct.sret_thunk::Agg" }>) %0)
// CHECK32-NEXT: ret %"struct.sret_thunk::Agg"* %[[rv]]
// CHECK64-LABEL: define linkonce_odr dso_local void @"?foo@C@sret_thunk@@W7EAA?AUAgg@2@U32@@Z"
return sum;
}
-// CHECK-LABEL: define dso_local i32 @"?foo@@YAHUA@@ZZ"(<{ %struct.A }>* inalloca %0, ...)
+// CHECK-LABEL: define dso_local i32 @"?foo@@YAHUA@@ZZ"(<{ %struct.A }>* inalloca(<{ %struct.A }>) %0, ...)
int main() {
return foo(A(3), 1, 2, 3);
}
// CHECK-LABEL: define dso_local i32 @main()
// CHECK: %[[argmem:[^ ]*]] = alloca inalloca <{ %struct.A, i32, i32, i32 }>
-// CHECK: call i32 {{.*bitcast.*}}@"?foo@@YAHUA@@ZZ"{{.*}}(<{ %struct.A, i32, i32, i32 }>* inalloca %[[argmem]])
+// CHECK: call i32 {{.*bitcast.*}}@"?foo@@YAHUA@@ZZ"{{.*}}(<{ %struct.A, i32, i32, i32 }>* inalloca(<{ %struct.A, i32, i32, i32 }>) %[[argmem]])
void varargs_zero(...);
void varargs_one(int, ...);
}
// CHECK-LABEL: define dso_local void @"?call_var_args@@YAXXZ"()
-// CHECK: call void {{.*bitcast.*varargs_zero.*}}(<{ %struct.A }>* inalloca %{{.*}})
-// CHECK: call void {{.*bitcast.*varargs_one.*}}(<{ i32, %struct.A }>* inalloca %{{.*}})
-// CHECK: call void {{.*bitcast.*varargs_two.*}}(<{ i32, i32, %struct.A }>* inalloca %{{.*}})
-// CHECK: call void {{.*bitcast.*varargs_three.*}}(<{ i32, i32, i32, %struct.A }>* inalloca %{{.*}})
+// CHECK: call void {{.*bitcast.*varargs_zero.*}}(<{ %struct.A }>* inalloca(<{ %struct.A }>) %{{.*}})
+// CHECK: call void {{.*bitcast.*varargs_one.*}}(<{ i32, %struct.A }>* inalloca(<{ i32, %struct.A }>) %{{.*}})
+// CHECK: call void {{.*bitcast.*varargs_two.*}}(<{ i32, i32, %struct.A }>* inalloca(<{ i32, i32, %struct.A }>) %{{.*}})
+// CHECK: call void {{.*bitcast.*varargs_three.*}}(<{ i32, i32, i32, %struct.A }>* inalloca(<{ i32, i32, i32, %struct.A }>) %{{.*}})
// CHECK-LABEL: declare dso_local void @"?varargs_zero@@YAXZZ"(...)
// CHECK-LABEL: declare dso_local void @"?varargs_one@@YAXHZZ"(i32, ...)
// WIN32: invoke x86_thiscallcc %struct.A* @"??0A@@QAE@XZ"
// WIN32: store i1 false, i1* %[[isactive]]
//
-// WIN32: invoke i32 @"?TakesTwo@@YAHUA@@0@Z"([[argmem_ty]]* inalloca %[[argmem]])
+// WIN32: invoke i32 @"?TakesTwo@@YAHUA@@0@Z"([[argmem_ty]]* inalloca([[argmem_ty]]) %[[argmem]])
// Destroy the two const ref temporaries.
// WIN32: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}})
// WIN32: call x86_thiscallcc void @"??1A@@QAE@XZ"({{.*}})
// WIN32: declare dso_local void @"{{.*take_bools_and_chars.*}}"
// WIN32: (<{ i8, [3 x i8], i8, [3 x i8], %struct.SmallWithDtor,
-// WIN32: i8, [3 x i8], i8, [3 x i8], i32, i8, [3 x i8] }>* inalloca)
+// WIN32: i8, [3 x i8], i8, [3 x i8], i32, i8, [3 x i8] }>* inalloca(<{ i8, [3 x i8], i8, [3 x i8], %struct.SmallWithDtor, i8, [3 x i8], i8, [3 x i8], i32, i8, [3 x i8] }>)
void take_bools_and_chars(char a, char b, SmallWithDtor c, char d, bool e, int f, bool g);
void call_bools_and_chars() {
take_bools_and_chars('A', 'B', SmallWithDtor(), 'D', true, 13, false);
// Test that dtors are invoked in the callee.
void small_arg_with_dtor(SmallWithDtor s) {}
-// WIN32: define dso_local void @"?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(<{ %struct.SmallWithDtor }>* inalloca %0) {{.*}} {
+// WIN32: define dso_local void @"?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(<{ %struct.SmallWithDtor }>* inalloca(<{ %struct.SmallWithDtor }>) %0) {{.*}} {
// WIN32: call x86_thiscallcc void @"??1SmallWithDtor@@QAE@XZ"
// WIN32: }
// WIN64: define dso_local void @"?small_arg_with_dtor@@YAXUSmallWithDtor@@@Z"(i32 %s.coerce) {{.*}} {
void small_arg_with_vftable(SmallWithVftable s) {}
// LINUX-LABEL: define{{.*}} void @_Z22small_arg_with_vftable16SmallWithVftable(%struct.SmallWithVftable* %s)
-// WIN32: define dso_local void @"?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(<{ %struct.SmallWithVftable }>* inalloca %0)
+// WIN32: define dso_local void @"?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(<{ %struct.SmallWithVftable }>* inalloca(<{ %struct.SmallWithVftable }>) %0)
// WIN64: define dso_local void @"?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* %s)
// WOA64: define dso_local void @"?small_arg_with_vftable@@YAXUSmallWithVftable@@@Z"(%struct.SmallWithVftable* %s)
void medium_arg_with_copy_ctor(MediumWithCopyCtor s) {}
// LINUX-LABEL: define{{.*}} void @_Z25medium_arg_with_copy_ctor18MediumWithCopyCtor(%struct.MediumWithCopyCtor* %s)
-// WIN32: define dso_local void @"?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(<{ %struct.MediumWithCopyCtor }>* inalloca %0)
+// WIN32: define dso_local void @"?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(<{ %struct.MediumWithCopyCtor }>* inalloca(<{ %struct.MediumWithCopyCtor }>) %0)
// WIN64: define dso_local void @"?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* %s)
// WOA: define dso_local arm_aapcs_vfpcc void @"?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* %s)
// WOA64: define dso_local void @"?medium_arg_with_copy_ctor@@YAXUMediumWithCopyCtor@@@Z"(%struct.MediumWithCopyCtor* %s)
};
void g(X) {
}
-// WIN32: define dso_local void @"?g@@YAXUX@@@Z"(<{ %struct.X, [3 x i8] }>* inalloca %0) {{.*}} {
+// WIN32: define dso_local void @"?g@@YAXUX@@@Z"(<{ %struct.X, [3 x i8] }>* inalloca(<{ %struct.X, [3 x i8] }>) %0) {{.*}} {
// WIN32: call x86_thiscallcc void @"??1X@@QAE@XZ"(%struct.X* {{.*}})
// WIN32: }
void f() {
// WIN32: call void @llvm.memcpy
// WIN32: getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 0
// WIN32: call x86_thiscallcc %"struct.test2::NonTrivial"* @"??0NonTrivial@test2@@QAE@XZ"
-// WIN32: call i32 @"?foo@test2@@YAHUNonTrivial@1@UPOD@1@@Z"([[argmem_ty]]* inalloca %argmem)
+// WIN32: call i32 @"?foo@test2@@YAHUNonTrivial@1@UPOD@1@@Z"([[argmem_ty]]* inalloca([[argmem_ty]]) %argmem)
// WIN32: ret void
// WIN32: }
int a;
};
void foo(NonTrivial a, bool b) { }
-// WIN32-LABEL: define dso_local void @"?foo@test3@@YAXUNonTrivial@1@_N@Z"(<{ %"struct.test3::NonTrivial", i8, [3 x i8] }>* inalloca %0)
+// WIN32-LABEL: define dso_local void @"?foo@test3@@YAXUNonTrivial@1@_N@Z"(<{ %"struct.test3::NonTrivial", i8, [3 x i8] }>* inalloca(<{ %"struct.test3::NonTrivial", i8, [3 x i8] }>) %0)
}
// WIN32: %[[gep2:[^ ]*]] = getelementptr inbounds [[argmem_ty]], [[argmem_ty]]* %[[argmem]], i32 0, i32 0
// WIN32: %[[addr:[^ ]*]] = bitcast {}** %[[gep2]] to void [[dst_ty]]*
// WIN32: store void [[dst_ty]] %[[a2]], void [[dst_ty]]* %[[addr]], align 4
-// WIN32: call void @"?fn1@@YAXP6AXUForwardDeclare1@@@ZUSmallWithDtor@@@Z"([[argmem_ty]]* inalloca %[[argmem]])
+// WIN32: call void @"?fn1@@YAXP6AXUForwardDeclare1@@@ZUSmallWithDtor@@@Z"([[argmem_ty]]* inalloca([[argmem_ty]]) %[[argmem]])
namespace pr30293 {
// Virtual methods living in a secondary vtable take i8* as their 'this'
// WIN32-LABEL: define dso_local x86_thiscallcc void @"?g@C@pr30293@@QAEXXZ"(%"struct.pr30293::C"* {{[^,]*}} %this)
// WIN32: call x86_thiscallcc %struct.SmallWithDtor* @"??0SmallWithDtor@@QAE@XZ"
-// WIN32: call void @"?h@C@pr30293@@UAAXUSmallWithDtor@@@Z"(<{ i8*, %struct.SmallWithDtor }>* inalloca %{{[^,)]*}})
-// WIN32: declare dso_local void @"?h@C@pr30293@@UAAXUSmallWithDtor@@@Z"(<{ i8*, %struct.SmallWithDtor }>* inalloca)
+// WIN32: call void @"?h@C@pr30293@@UAAXUSmallWithDtor@@@Z"(<{ i8*, %struct.SmallWithDtor }>* inalloca(<{ i8*, %struct.SmallWithDtor }>) %{{[^,)]*}})
+// WIN32: declare dso_local void @"?h@C@pr30293@@UAAXUSmallWithDtor@@@Z"(<{ i8*, %struct.SmallWithDtor }>* inalloca(<{ i8*, %struct.SmallWithDtor }>))
// WIN64-LABEL: define dso_local void @"?g@C@pr30293@@QEAAXXZ"(%"struct.pr30293::C"* {{[^,]*}} %this)
// WIN64: declare dso_local void @"?h@C@pr30293@@UEAAXUSmallWithDtor@@@Z"(i8*, i32)
// CHECK-LABEL: define dso_local void @"?f@cdecl_inalloca@@YAXPAUC@1@@Z"(%"struct.cdecl_inalloca::C"* %c)
// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* @"??_9C@cdecl_inalloca@@$BA@AA" to void (%"struct.cdecl_inalloca::C"*)*)(%"struct.cdecl_inalloca::C"* {{[^,]*}} %{{.*}})
-// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* @"??_9C@cdecl_inalloca@@$BA@AA" to void (<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>*)*)(<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>* inalloca %{{.*}})
+// CHECK: call void bitcast (void (%"struct.cdecl_inalloca::C"*, ...)* @"??_9C@cdecl_inalloca@@$BA@AA" to void (<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>*)*)(<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>* inalloca(<{ %"struct.cdecl_inalloca::C"*, %"struct.cdecl_inalloca::Big" }>) %{{.*}})
// CHECK-LABEL: define linkonce_odr void @"??_9C@cdecl_inalloca@@$BA@AA"(%"struct.cdecl_inalloca::C"* %this, ...) {{.*}} comdat
// CHECK: musttail call void (%"struct.cdecl_inalloca::C"*, ...) %{{.*}}(%"struct.cdecl_inalloca::C"* %{{.*}}, ...)
whatsthis = this;
}
-// BITCODE-LABEL: define dso_local void @"?g@C@pr30293@@UAAXUNonTrivial@2@@Z"(<{ i8*, %"struct.pr30293::NonTrivial" }>* inalloca %0)
+// BITCODE-LABEL: define dso_local void @"?g@C@pr30293@@UAAXUNonTrivial@2@@Z"(<{ i8*, %"struct.pr30293::NonTrivial" }>* inalloca(<{ i8*, %"struct.pr30293::NonTrivial" }>) %0)
// BITCODE: %[[thisaddr:[^ ]*]] = getelementptr inbounds <{ i8*, %"struct.pr30293::NonTrivial" }>, <{ i8*, %"struct.pr30293::NonTrivial" }>* {{.*}}, i32 0, i32 0
// BITCODE: %[[thisaddr1:[^ ]*]] = bitcast i8** %[[thisaddr]] to %"struct.pr30293::C"**
// BITCODE: %[[this1:[^ ]*]] = load %"struct.pr30293::C"*, %"struct.pr30293::C"** %[[thisaddr1]], align 4
};
C c;
-// CHECK-LABEL: define linkonce_odr dso_local x86_thiscallcc void @"?f@C@@G3AEXUNonTrivial@@@Z"(%class.C* %this, <{ %struct.NonTrivial }>* inalloca %0)
+// CHECK-LABEL: define linkonce_odr dso_local x86_thiscallcc void @"?f@C@@G3AEXUNonTrivial@@@Z"(%class.C* %this, <{ %struct.NonTrivial }>* inalloca(<{ %struct.NonTrivial }>) %0)
// CHECK-NOT: invoke
-// CHECK: musttail call x86_thiscallcc void @"?f@C@@EAEXUNonTrivial@@@Z"(%class.C* %{{.*}}, <{ %struct.NonTrivial }>* inalloca %0)
+// CHECK: musttail call x86_thiscallcc void @"?f@C@@EAEXUNonTrivial@@@Z"(%class.C* %{{.*}}, <{ %struct.NonTrivial }>* inalloca(<{ %struct.NonTrivial }>) %0)
// CHECK-NEXT: ret void
// CHECK-LABEL: define dso_local void @"?test@@YAXUX@@@Z"
// X86: %[[argmem:[^ ]*]] = alloca inalloca <{ %struct.X }>
- // X86: call void (<{ %struct.X }>*, ...) bitcast (void (...)* @"?vararg@@YAXZZ" to void (<{ %struct.X }>*, ...)*)(<{ %struct.X }>* inalloca %[[argmem]])
+ // X86: call void (<{ %struct.X }>*, ...) bitcast (void (...)* @"?vararg@@YAXZZ" to void (<{ %struct.X }>*, ...)*)(<{ %struct.X }>* inalloca(<{ %struct.X }>) %[[argmem]])
// X64: alloca %struct.X
}
@end
-// CHECK-GNUSTEP: define internal void @_i_C__object_struct_(<{ %0*, i8*, i8*, %struct.S, [3 x i8] }>* inalloca %0)
-// CHECK-DARWIN: define internal void @"\01-[C object:struct:]"(<{ %0*, i8*, i8*, %struct.S, [3 x i8] }>* inalloca %0)
+// CHECK-GNUSTEP: define internal void @_i_C__object_struct_(<{ %0*, i8*, i8*, %struct.S, [3 x i8] }>* inalloca(<{ %0*, i8*, i8*, %struct.S, [3 x i8] }>) %0)
+// CHECK-DARWIN: define internal void @"\01-[C object:struct:]"(<{ %0*, i8*, i8*, %struct.S, [3 x i8] }>* inalloca(<{ %0*, i8*, i8*, %struct.S, [3 x i8] }>) %0)
// CHECK: %obj = getelementptr inbounds <{ %0*, i8*, i8*, %struct.S, [3 x i8] }>, <{ %0*, i8*, i8*, %struct.S, [3 x i8] }>* %0, i32 0, i32 2
// CHECK: %[[INSTANCE:[0-9]+]] = load i8*, i8** %obj, align 4
// CHECK: call void @llvm.objc.storeStrong(i8** %obj, i8* %[[INSTANCE]])
// Verify that we destruct things from left to right in the MS C++ ABI: a, b, c, d.
//
// CHECK-LABEL: define dso_local void @"?test_arc_order@@YAXUA@@PAUobjc_object@@01@Z"
-// CHECK: (<{ %struct.A, i8*, %struct.A, i8* }>* inalloca %0)
+// CHECK: (<{ %struct.A, i8*, %struct.A, i8* }>* inalloca(<{ %struct.A, i8*, %struct.A, i8* }>) %0)
void test_arc_order(A a, id __attribute__((ns_consumed)) b , A c, id __attribute__((ns_consumed)) d) {
// CHECK: call x86_thiscallcc void @"??1A@@QAE@XZ"(%struct.A* {{[^,]*}} %{{.*}})
// CHECK: call void @llvm.objc.storeStrong(i8** %{{.*}}, i8* null)
"alwaysinline",
"builtin",
"convergent",
- "inalloca",
"inlinehint",
"inreg",
"jumptable",
.. _attr_inalloca:
-``inalloca``
+``inalloca(<ty>)``
The ``inalloca`` argument attribute allows the caller to take the
address of outgoing stack arguments. An ``inalloca`` argument must
must be cleared off with :ref:`llvm.stackrestore
<int_stackrestore>`.
+ The inalloca attribute requires a type argument, which must be the
+ same as the pointee type of the argument.
+
See :doc:`InAlloca` for more information on how to use this
attribute.
Changes to the LLVM IR
----------------------
-* ...
+* The ``inalloca`` attribute now has a mandatory type field, similar
+ to ``byval`` and ``sret``.
Changes to building LLVM
/// If this is a byref argument, return its type.
Type *getParamByRefType() const;
+ /// If this is an inalloca argument, return its type.
+ Type *getParamInAllocaType() const;
+
/// Return true if this argument has the nest attribute.
bool hasNestAttr() const;
static Attribute getWithStructRetType(LLVMContext &Context, Type *Ty);
static Attribute getWithByRefType(LLVMContext &Context, Type *Ty);
static Attribute getWithPreallocatedType(LLVMContext &Context, Type *Ty);
+ static Attribute getWithInAllocaType(LLVMContext &Context, Type *Ty);
/// For a typed attribute, return the equivalent attribute with the type
/// changed to \p ReplacementTy.
bool hasAttribute(StringRef Val) const;
/// Return the attribute's kind as an enum (Attribute::AttrKind). This
- /// requires the attribute to be an enum or integer attribute.
+ /// requires the attribute to be an enum, integer, or type attribute.
Attribute::AttrKind getKindAsEnum() const;
/// Return the attribute's value as an integer. This requires that the
Type *getStructRetType() const;
Type *getByRefType() const;
Type *getPreallocatedType() const;
+ Type *getInAllocaType() const;
std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
std::pair<unsigned, unsigned> getVScaleRangeArgs() const;
std::string getAsString(bool InAttrGrp = false) const;
/// Return the preallocated type for the specified function parameter.
Type *getParamPreallocatedType(unsigned ArgNo) const;
+ /// Return the inalloca type for the specified function parameter.
+ Type *getParamInAllocaType(unsigned ArgNo) const;
+
/// Get the stack alignment.
MaybeAlign getStackAlignment(unsigned Index) const;
Type *StructRetType = nullptr;
Type *ByRefType = nullptr;
Type *PreallocatedType = nullptr;
+ Type *InAllocaType = nullptr;
public:
AttrBuilder() = default;
/// Retrieve the preallocated type.
Type *getPreallocatedType() const { return PreallocatedType; }
+ /// Retrieve the inalloca type.
+ Type *getInAllocaType() const { return InAllocaType; }
+
/// Retrieve the allocsize args, if the allocsize attribute exists. If it
/// doesn't exist, pair(0, 0) is returned.
std::pair<unsigned, Optional<unsigned>> getAllocSizeArgs() const;
/// This turns a preallocated type into the form used internally in Attribute.
AttrBuilder &addPreallocatedAttr(Type *Ty);
+ /// This turns an inalloca type into the form used internally in Attribute.
+ AttrBuilder &addInAllocaAttr(Type *Ty);
+
/// Add an allocsize attribute, using the representation returned by
/// Attribute.getIntValue().
AttrBuilder &addAllocSizeAttrFromRawRepr(uint64_t RawAllocSizeRepr);
def InaccessibleMemOrArgMemOnly : EnumAttr<"inaccessiblemem_or_argmemonly">;
/// Pass structure in an alloca.
-def InAlloca : EnumAttr<"inalloca">;
+def InAlloca : TypeAttr<"inalloca">;
/// Source said inlining was desirable.
def InlineHint : EnumAttr<"inlinehint">;
return AttributeSets.getParamStructRetType(ArgNo);
}
+ /// Extract the inalloca type for a parameter.
+ Type *getParamInAllocaType(unsigned ArgNo) const {
+ return AttributeSets.getParamInAllocaType(ArgNo);
+ }
+
/// Extract the byref type for a parameter.
Type *getParamByRefType(unsigned ArgNo) const {
return AttributeSets.getParamByRefType(ArgNo);
B.addPreallocatedAttr(Ty);
continue;
}
+ case lltok::kw_inalloca: {
+ Type *Ty;
+ if (parseInalloca(Ty))
+ return true;
+ B.addInAllocaAttr(Ty);
+ continue;
+ }
case lltok::kw_dereferenceable: {
uint64_t Bytes;
if (parseOptionalDerefAttrBytes(lltok::kw_dereferenceable, Bytes))
B.addByRefAttr(Ty);
continue;
}
- case lltok::kw_inalloca: B.addAttribute(Attribute::InAlloca); break;
case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break;
case lltok::kw_nest: B.addAttribute(Attribute::Nest); break;
case lltok::kw_noundef:
return parseRequiredTypeAttr(Result, lltok::kw_preallocated);
}
+/// parseInalloca
+/// ::= inalloca(<ty>)
+bool LLParser::parseInalloca(Type *&Result) {
+ return parseRequiredTypeAttr(Result, lltok::kw_inalloca);
+}
+
/// parseByRef
/// ::= byref(<type>)
bool LLParser::parseByRef(Type *&Result) {
bool inAttrGrp, LocTy &BuiltinLoc);
bool parseRequiredTypeAttr(Type *&Result, lltok::Kind AttrName);
bool parsePreallocated(Type *&Result);
+ bool parseInalloca(Type *&Result);
bool parseByRef(Type *&Result);
// Module Summary Index Parsing.
B.addByValAttr(nullptr);
else if (Kind == Attribute::StructRet)
B.addStructRetAttr(nullptr);
+ else if (Kind == Attribute::InAlloca)
+ B.addInAllocaAttr(nullptr);
B.addAttribute(Kind);
} else if (Record[i] == 1) { // Integer attribute
B.addByRefAttr(getTypeByID(Record[++i]));
} else if (Kind == Attribute::Preallocated) {
B.addPreallocatedAttr(getTypeByID(Record[++i]));
+ } else if (Kind == Attribute::InAlloca) {
+ B.addInAllocaAttr(HasType ? getTypeByID(Record[++i]) : nullptr);
}
}
}
// argument's pointee type. There should be no opaque pointers where the byval
// type is implicit.
for (unsigned i = 0; i != Func->arg_size(); ++i) {
- for (Attribute::AttrKind Kind : {Attribute::ByVal, Attribute::StructRet}) {
+ for (Attribute::AttrKind Kind : {Attribute::ByVal, Attribute::StructRet,
+ Attribute::InAlloca}) {
if (!Func->hasParamAttribute(i, Kind))
continue;
Type *PTy = cast<FunctionType>(FullFTy)->getParamType(i);
Type *PtrEltTy = getPointerElementFlatType(PTy);
- Attribute NewAttr =
- Kind == Attribute::ByVal
- ? Attribute::getWithByValType(Context, PtrEltTy)
- : Attribute::getWithStructRetType(Context, PtrEltTy);
+ Attribute NewAttr;
+ switch (Kind) {
+ case Attribute::ByVal:
+ NewAttr = Attribute::getWithByValType(Context, PtrEltTy);
+ break;
+ case Attribute::StructRet:
+ NewAttr = Attribute::getWithStructRetType(Context, PtrEltTy);
+ break;
+ case Attribute::InAlloca:
+ NewAttr = Attribute::getWithInAllocaType(Context, PtrEltTy);
+ break;
+ default:
+ llvm_unreachable("not an upgraded type attribute");
+ }
+
Func->addParamAttr(i, NewAttr);
}
}
void BitcodeReader::propagateByValSRetTypes(CallBase *CB,
ArrayRef<Type *> ArgsFullTys) {
for (unsigned i = 0; i != CB->arg_size(); ++i) {
- for (Attribute::AttrKind Kind : {Attribute::ByVal, Attribute::StructRet}) {
+ for (Attribute::AttrKind Kind : {Attribute::ByVal, Attribute::StructRet,
+ Attribute::InAlloca}) {
if (!CB->paramHasAttr(i, Kind))
continue;
CB->removeParamAttr(i, Kind);
Type *PtrEltTy = getPointerElementFlatType(ArgsFullTys[i]);
- Attribute NewAttr =
- Kind == Attribute::ByVal
- ? Attribute::getWithByValType(Context, PtrEltTy)
- : Attribute::getWithStructRetType(Context, PtrEltTy);
+ Attribute NewAttr;
+ switch (Kind) {
+ case Attribute::ByVal:
+ NewAttr = Attribute::getWithByValType(Context, PtrEltTy);
+ break;
+ case Attribute::StructRet:
+ NewAttr = Attribute::getWithStructRetType(Context, PtrEltTy);
+ break;
+ case Attribute::InAlloca:
+ NewAttr = Attribute::getWithInAllocaType(Context, PtrEltTy);
+ break;
+ default:
+ llvm_unreachable("not an upgraded type attribute");
+ }
+
CB->addParamAttr(i, NewAttr);
}
}
return;
}
- assert((Attr.hasAttribute(Attribute::ByVal) ||
- Attr.hasAttribute(Attribute::StructRet) ||
- Attr.hasAttribute(Attribute::ByRef) ||
- Attr.hasAttribute(Attribute::Preallocated)) &&
- "unexpected type attr");
-
if (Attr.hasAttribute(Attribute::ByVal)) {
Out << "byval";
} else if (Attr.hasAttribute(Attribute::StructRet)) {
Out << "sret";
} else if (Attr.hasAttribute(Attribute::ByRef)) {
Out << "byref";
- } else {
+ } else if (Attr.hasAttribute(Attribute::Preallocated)) {
Out << "preallocated";
+ } else if (Attr.hasAttribute(Attribute::InAlloca)) {
+ Out << "inalloca";
+ } else {
+ llvm_unreachable("unexpected type attr");
}
if (Type *Ty = Attr.getValueAsType()) {
Type *getStructRetType() const;
Type *getByRefType() const;
Type *getPreallocatedType() const;
+ Type *getInAllocaType() const;
using iterator = const Attribute *;
return get(Context, Preallocated, Ty);
}
+Attribute Attribute::getWithInAllocaType(LLVMContext &Context, Type *Ty) {
+ return get(Context, InAlloca, Ty);
+}
+
Attribute
Attribute::getWithAllocSizeArgs(LLVMContext &Context, unsigned ElemSizeArg,
const Optional<unsigned> &NumElemsArg) {
return "inaccessiblememonly";
if (hasAttribute(Attribute::InaccessibleMemOrArgMemOnly))
return "inaccessiblemem_or_argmemonly";
- if (hasAttribute(Attribute::InAlloca))
- return "inalloca";
if (hasAttribute(Attribute::InlineHint))
return "inlinehint";
if (hasAttribute(Attribute::InReg))
if (hasAttribute(Attribute::MustProgress))
return "mustprogress";
- const bool IsByVal = hasAttribute(Attribute::ByVal);
- if (IsByVal || hasAttribute(Attribute::StructRet)) {
+ if (isTypeAttribute()) {
std::string Result;
- Result += IsByVal ? "byval" : "sret";
- if (Type *Ty = getValueAsType()) {
- raw_string_ostream OS(Result);
- Result += '(';
- Ty->print(OS, false, true);
- OS.flush();
- Result += ')';
+ raw_string_ostream OS(Result);
+
+ switch (getKindAsEnum()) {
+ case Attribute::ByVal:
+ Result += "byval";
+ break;
+ case Attribute::StructRet:
+ Result += "sret";
+ break;
+ case Attribute::ByRef:
+ Result += "byref";
+ break;
+ case Attribute::Preallocated:
+ Result += "preallocated";
+ break;
+ case Attribute::InAlloca:
+ Result += "inalloca";
+ break;
+ default:
+ llvm_unreachable("unhandled type attribute");
}
- return Result;
- }
- const bool IsByRef = hasAttribute(Attribute::ByRef);
- if (IsByRef || hasAttribute(Attribute::Preallocated)) {
- std::string Result = IsByRef ? "byref" : "preallocated";
- raw_string_ostream OS(Result);
Result += '(';
getValueAsType()->print(OS, false, true);
OS.flush();
return SetNode ? SetNode->getPreallocatedType() : nullptr;
}
+Type *AttributeSet::getInAllocaType() const {
+ return SetNode ? SetNode->getInAllocaType() : nullptr;
+}
+
std::pair<unsigned, Optional<unsigned>> AttributeSet::getAllocSizeArgs() const {
return SetNode ? SetNode->getAllocSizeArgs()
: std::pair<unsigned, Optional<unsigned>>(0, 0);
case Attribute::Preallocated:
Attr = Attribute::getWithPreallocatedType(C, B.getPreallocatedType());
break;
+ case Attribute::InAlloca:
+ Attr = Attribute::getWithInAllocaType(C, B.getInAllocaType());
+ break;
case Attribute::Alignment:
assert(B.getAlignment() && "Alignment must be set");
Attr = Attribute::getWithAlignment(C, *B.getAlignment());
return nullptr;
}
+Type *AttributeSetNode::getInAllocaType() const {
+ if (auto A = findEnumAttribute(Attribute::InAlloca))
+ return A->getValueAsType();
+ return nullptr;
+}
+
uint64_t AttributeSetNode::getDereferenceableBytes() const {
if (auto A = findEnumAttribute(Attribute::Dereferenceable))
return A->getDereferenceableBytes();
return getAttributes(Index + FirstArgIndex).getPreallocatedType();
}
+Type *AttributeList::getParamInAllocaType(unsigned Index) const {
+ return getAttributes(Index + FirstArgIndex).getInAllocaType();
+}
+
MaybeAlign AttributeList::getStackAlignment(unsigned Index) const {
return getAttributes(Index).getStackAlignment();
}
AllocSizeArgs = Attr.getValueAsInt();
else if (Kind == Attribute::VScaleRange)
VScaleRangeArgs = Attr.getValueAsInt();
+ else if (Kind == Attribute::InAlloca)
+ InAllocaType = Attr.getValueAsType();
+
return *this;
}
ByRefType = nullptr;
else if (Val == Attribute::Preallocated)
PreallocatedType = nullptr;
+ else if (Val == Attribute::InAlloca)
+ InAllocaType = nullptr;
else if (Val == Attribute::Dereferenceable)
DerefBytes = 0;
else if (Val == Attribute::DereferenceableOrNull)
return *this;
}
+AttrBuilder &AttrBuilder::addInAllocaAttr(Type *Ty) {
+ Attrs[Attribute::InAlloca] = true;
+ InAllocaType = Ty;
+ return *this;
+}
+
AttrBuilder &AttrBuilder::merge(const AttrBuilder &B) {
// FIXME: What if both have alignments, but they don't match?!
if (!Alignment)
if (!PreallocatedType)
PreallocatedType = B.PreallocatedType;
+ if (!InAllocaType)
+ InAllocaType = B.InAllocaType;
+
if (!VScaleRangeArgs)
VScaleRangeArgs = B.VScaleRangeArgs;
if (B.PreallocatedType)
PreallocatedType = nullptr;
+ if (B.InAllocaType)
+ InAllocaType = nullptr;
+
if (B.VScaleRangeArgs)
VScaleRangeArgs = 0;
DerefBytes == B.DerefBytes && ByValType == B.ByValType &&
StructRetType == B.StructRetType && ByRefType == B.ByRefType &&
PreallocatedType == B.PreallocatedType &&
+ InAllocaType == B.InAllocaType &&
VScaleRangeArgs == B.VScaleRangeArgs;
}
.addAttribute(Attribute::ReadOnly)
.addAttribute(Attribute::InAlloca)
.addPreallocatedAttr(Ty)
+ .addInAllocaAttr(Ty)
.addByValAttr(Ty)
.addStructRetAttr(Ty)
.addByRefAttr(Ty);
return ByRefTy;
if (Type *PreAllocTy = ParamAttrs.getPreallocatedType())
return PreAllocTy;
+ if (Type *InAllocaTy = ParamAttrs.getInAllocaType())
+ return InAllocaTy;
// FIXME: sret and inalloca always depends on pointee element type. It's also
// possible for byval to miss it.
return getParent()->getParamByRefType(getArgNo());
}
+Type *Argument::getParamInAllocaType() const {
+ assert(getType()->isPointerTy() && "Only pointers have inalloca types");
+ return getParent()->getParamInAllocaType(getArgNo());
+}
+
uint64_t Argument::getDereferenceableBytes() const {
assert(getType()->isPointerTy() &&
"Only pointers have dereferenceable bytes");
Assert(Attrs.getPreallocatedType() == PTy->getElementType(),
"Attribute 'preallocated' type does not match parameter!", V);
}
+
+ if (Attrs.hasAttribute(Attribute::InAlloca)) {
+ Assert(Attrs.getInAllocaType() == PTy->getElementType(),
+ "Attribute 'inalloca' type does not match parameter!", V);
+ }
} else {
Assert(!Attrs.hasAttribute(Attribute::ByVal),
"Attribute 'byval' only applies to parameters with pointer type!",
AttributeList IRLinker::mapAttributeTypes(LLVMContext &C, AttributeList Attrs) {
for (unsigned i = 0; i < Attrs.getNumAttrSets(); ++i) {
for (Attribute::AttrKind TypedAttr :
- {Attribute::ByVal, Attribute::StructRet, Attribute::ByRef}) {
+ {Attribute::ByVal, Attribute::StructRet, Attribute::ByRef,
+ Attribute::InAlloca}) {
if (Attrs.hasAttribute(i, TypedAttr)) {
if (Type *Ty = Attrs.getAttribute(i, TypedAttr).getValueAsType()) {
Attrs = Attrs.replaceAttributeType(C, i, TypedAttr, TypeMap.get(Ty));
AttributeList Attrs = CB->getAttributes();
for (unsigned i = 0; i < Attrs.getNumAttrSets(); ++i) {
for (Attribute::AttrKind TypedAttr :
- {Attribute::ByVal, Attribute::StructRet, Attribute::ByRef}) {
+ {Attribute::ByVal, Attribute::StructRet, Attribute::ByRef,
+ Attribute::InAlloca}) {
if (Type *Ty = Attrs.getAttribute(i, TypedAttr).getValueAsType()) {
Attrs = Attrs.replaceAttributeType(C, i, TypedAttr,
TypeMapper->remapType(Ty));
--- /dev/null
+; RUN: not llvm-as < %s 2>&1 | FileCheck %s
+
+; CHECK: <stdin>:[[@LINE+1]]:40: error: expected '('{{$}}
+define void @test_inalloca(i8* inalloca) {
+ ret void
+}
declare void @llvm.immarg.byval(i32* byval(i32) immarg)
; CHECK: Attribute 'immarg' is incompatible with other attributes
-declare void @llvm.immarg.inalloca(i32* inalloca immarg)
+declare void @llvm.immarg.inalloca(i32* inalloca(i32) immarg)
; CHECK: Attribute 'immarg' is incompatible with other attributes
declare void @llvm.immarg.inreg(i32 inreg immarg)
ret void;
}
-define void @f36(i8* inalloca %0) {
-; CHECK: define void @f36(i8* inalloca %0) {
+define void @f36(i8* inalloca(i8) %0) {
+; CHECK: define void @f36(i8* inalloca(i8) %0) {
ret void
}
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
declare void @f.param.inalloca(i8* inalloca)
-; CHECK: declare void @f.param.inalloca(i8* inalloca)
+; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
declare void @f.param.sret(i8* sret(i8))
; CHECK: declare void @f.param.sret(i8* sret(i8))
declare void @f.param.noalias(i8* noalias)
define void @instructions.call_musttail(i8* inalloca %val) {
musttail call void @f.param.inalloca(i8* inalloca %val)
- ; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
+ ; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
ret void
}
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
declare void @f.param.inalloca(i8* inalloca)
-; CHECK: declare void @f.param.inalloca(i8* inalloca)
+; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
declare void @f.param.sret(i8* sret(i8))
; CHECK: declare void @f.param.sret(i8* sret(i8))
declare void @f.param.noalias(i8* noalias)
define void @instructions.call_musttail(i8* inalloca %val) {
musttail call void @f.param.inalloca(i8* inalloca %val)
- ; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
+ ; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
ret void
}
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
declare void @f.param.inalloca(i8* inalloca)
-; CHECK: declare void @f.param.inalloca(i8* inalloca)
+; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
declare void @f.param.sret(i8* sret(i8))
; CHECK: declare void @f.param.sret(i8* sret(i8))
declare void @f.param.noalias(i8* noalias)
define void @instructions.call_musttail(i8* inalloca %val) {
musttail call void @f.param.inalloca(i8* inalloca %val)
- ; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
+ ; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
ret void
}
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
declare void @f.param.inalloca(i8* inalloca)
-; CHECK: declare void @f.param.inalloca(i8* inalloca)
+; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
declare void @f.param.sret(i8* sret(i8))
; CHECK: declare void @f.param.sret(i8* sret(i8))
declare void @f.param.noalias(i8* noalias)
define void @instructions.call_musttail(i8* inalloca %val) {
musttail call void @f.param.inalloca(i8* inalloca %val)
- ; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
+ ; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
ret void
}
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
declare void @f.param.inalloca(i8* inalloca)
-; CHECK: declare void @f.param.inalloca(i8* inalloca)
+; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
declare void @f.param.sret(i8* sret(i8))
; CHECK: declare void @f.param.sret(i8* sret(i8))
declare void @f.param.noalias(i8* noalias)
define void @instructions.call_musttail(i8* inalloca %val) {
musttail call void @f.param.inalloca(i8* inalloca %val)
- ; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
+ ; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
ret void
}
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
declare void @f.param.inalloca(i8* inalloca)
-; CHECK: declare void @f.param.inalloca(i8* inalloca)
+; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
declare void @f.param.sret(i8* sret(i8))
; CHECK: declare void @f.param.sret(i8* sret(i8))
declare void @f.param.noalias(i8* noalias)
define void @instructions.call_musttail(i8* inalloca %val) {
musttail call void @f.param.inalloca(i8* inalloca %val)
- ; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
+ ; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
ret void
}
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
declare void @f.param.inalloca(i8* inalloca)
-; CHECK: declare void @f.param.inalloca(i8* inalloca)
+; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
declare void @f.param.sret(i8* sret(i8))
; CHECK: declare void @f.param.sret(i8* sret(i8))
declare void @f.param.noalias(i8* noalias)
define void @instructions.call_musttail(i8* inalloca %val) {
musttail call void @f.param.inalloca(i8* inalloca %val)
- ; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
+ ; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
ret void
}
; CHECK: declare void @f.param.inreg(i8 inreg)
declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
; CHECK: declare void @f.param.byval({ i8, i8 }* byval({ i8, i8 }))
-declare void @f.param.inalloca(i8* inalloca)
-; CHECK: declare void @f.param.inalloca(i8* inalloca)
+declare void @f.param.inalloca(i8* inalloca(i8))
+; CHECK: declare void @f.param.inalloca(i8* inalloca(i8))
declare void @f.param.sret(i8* sret(i8))
; CHECK: declare void @f.param.sret(i8* sret(i8))
declare void @f.param.noalias(i8* noalias)
ret void
}
-define void @instructions.call_musttail(i8* inalloca %val) {
- musttail call void @f.param.inalloca(i8* inalloca %val)
- ; CHECK: musttail call void @f.param.inalloca(i8* inalloca %val)
+define void @instructions.call_musttail(i8* inalloca(i8) %val) {
+ musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
+ ; CHECK: musttail call void @f.param.inalloca(i8* inalloca(i8) %val)
ret void
}
--- /dev/null
+RUN: llvm-dis %p/Inputs/inalloca-upgrade.bc -o - | FileCheck %s
+
+Make sure we upgrade old-style IntAttribute inalloca records to a
+fully typed version correctly.
+
+CHECK: call void @bar({ i32*, i8 }* inalloca({ i32*, i8 }) %ptr)
+CHECK: invoke void @bar({ i32*, i8 }* inalloca({ i32*, i8 }) %ptr)
; inalloca should roundtrip.
-define void @foo(i32* inalloca %args) {
+define void @foo(i32* inalloca(i32) %args) {
ret void
}
-; CHECK-LABEL: define void @foo(i32* inalloca %args)
+; CHECK-LABEL: define void @foo(i32* inalloca(i32) %args)
define void @bar() {
; Use the maximum alignment, since we stuff our bit with alignment.
%args = alloca inalloca i32, align 536870912
- call void @foo(i32* inalloca %args)
+ call void @foo(i32* inalloca(i32) %args)
ret void
}
; CHECK-LABEL: define void @bar() {
; CHECK: %args = alloca inalloca i32, align 536870912
-; CHECK: call void @foo(i32* inalloca %args)
+; CHECK: call void @foo(i32* inalloca(i32) %args)
; CHECK: retl
-define void @avoid_inalloca(i32* inalloca %x) {
+define void @avoid_inalloca(i32* inalloca(i32) %x) {
entry:
%x.p.p = alloca i32*
store i32* %x, i32** %x.p.p
to label %invoke.cont unwind label %ehcleanup
invoke.cont: ; preds = %entry
- call void @takes_two(<{ %struct.A, %struct.A }>* inalloca nonnull %argmem)
+ call void @takes_two(<{ %struct.A, %struct.A }>* inalloca(<{ %struct.A, %struct.A }>) nonnull %argmem)
ret void
ehcleanup: ; preds = %entry
; CHECK: addl $8, %esp
; CHECK: retl
-declare void @takes_two(<{ %struct.A, %struct.A }>* inalloca) #0
+declare void @takes_two(<{ %struct.A, %struct.A }>* inalloca(<{ %struct.A, %struct.A }>)) #0
declare x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* returned) #0
%frame = type { %Foo, i32, %Foo }
-declare void @f(%frame* inalloca %a)
+declare void @f(%frame* inalloca(%frame) %a)
declare void @Foo_ctor(%Foo* %this)
; CHECK-NEXT: pushl
; CHECK-NEXT: calll _Foo_ctor
; CHECK: addl $4, %esp
- call void @f(%frame* inalloca %args)
+ call void @f(%frame* inalloca(%frame) %args)
; CHECK: calll _f
ret void
}
declare i8* @llvm.stacksave()
declare void @begin(%Iter* sret(%Iter))
declare void @plus(%Iter* sret(%Iter), %Iter*, i32)
-declare void @reverse(%frame.reverse* inalloca align 4)
+declare void @reverse(%frame.reverse* inalloca(%frame.reverse) align 4)
define i32 @main() personality i32 (...)* @pers {
%temp.lvalue = alloca %Iter
; CHECK: pushl %[[beg]]
; CHECK: calll _begin
- invoke void @reverse(%frame.reverse* inalloca align 4 %rev_args)
+ invoke void @reverse(%frame.reverse* inalloca(%frame.reverse) align 4 %rev_args)
to label %invoke.cont5 unwind label %lpad
invoke.cont5: ; preds = %invoke.cont
; This will compile successfully on x86 but not x86_64, because %b will become a
; register parameter.
-declare x86_thiscallcc i32 @f(i32 %a, i32* inalloca %b)
+declare x86_thiscallcc i32 @f(i32 %a, i32* inalloca(i32) %b)
define void @g() {
%b = alloca inalloca i32
store i32 2, i32* %b
- call x86_thiscallcc i32 @f(i32 0, i32* inalloca %b)
+ call x86_thiscallcc i32 @f(i32 0, i32* inalloca(i32) %b)
ret void
}
%Foo = type { i32, i32 }
-declare x86_stdcallcc void @f(%Foo* inalloca %a)
+declare x86_stdcallcc void @f(%Foo* inalloca(%Foo) %a)
declare x86_stdcallcc void @i(i32 %a)
define void @g() {
; CHECK: movl %esp, %eax
; CHECK: movl $13, (%eax)
; CHECK: movl $42, 4(%eax)
- call x86_stdcallcc void @f(%Foo* inalloca %b)
+ call x86_stdcallcc void @f(%Foo* inalloca(%Foo) %b)
; CHECK: calll _f@8
; CHECK-NOT: %esp
; CHECK: pushl
%Foo = type { i32, i32 }
-declare void @f(%Foo* inalloca %b)
+declare void @f(%Foo* inalloca(%Foo) %b)
define void @a() {
; CHECK-LABEL: _a:
; CHECK: movl %esp, %eax
; CHECK: movl $13, (%eax)
; CHECK: movl $42, 4(%eax)
- call void @f(%Foo* inalloca %b)
+ call void @f(%Foo* inalloca(%Foo) %b)
; CHECK: calll _f
ret void
}
-declare void @inreg_with_inalloca(i32 inreg %a, %Foo* inalloca %b)
+declare void @inreg_with_inalloca(i32 inreg %a, %Foo* inalloca(%Foo) %b)
define void @b() {
; CHECK-LABEL: _b:
; CHECK: movl %esp, %eax
; CHECK: movl $13, (%eax)
; CHECK: movl $42, 4(%eax)
- call void @inreg_with_inalloca(i32 inreg 1, %Foo* inalloca %b)
+ call void @inreg_with_inalloca(i32 inreg 1, %Foo* inalloca(%Foo) %b)
; CHECK: movl $1, %eax
; CHECK: calll _inreg_with_inalloca
ret void
}
-declare x86_thiscallcc void @thiscall_with_inalloca(i8* %a, %Foo* inalloca %b)
+declare x86_thiscallcc void @thiscall_with_inalloca(i8* %a, %Foo* inalloca(%Foo) %b)
define void @c() {
; CHECK-LABEL: _c:
; CHECK: movl %esp, %eax
; CHECK-DAG: movl $13, (%eax)
; CHECK-DAG: movl $42, 4(%eax)
- call x86_thiscallcc void @thiscall_with_inalloca(i8* null, %Foo* inalloca %b)
+ call x86_thiscallcc void @thiscall_with_inalloca(i8* null, %Foo* inalloca(%Foo) %b)
; CHECK-DAG: xorl %ecx, %ecx
; CHECK: calll _thiscall_with_inalloca
ret void
declare void @eightparams16(i16 %a, i16 %b, i16 %c, i16 %d, i16 %e, i16 %f, i16 %g, i16 %h)
declare void @eightparams64(i64 %a, i64 %b, i64 %c, i64 %d, i64 %e, i64 %f, i64 %g, i64 %h)
declare void @struct(%struct.s* byval(%struct.s) %a, i32 %b, i32 %c, i32 %d)
-declare void @inalloca(<{ %struct.s }>* inalloca)
+declare void @inalloca(<{ %struct.s }>* inalloca(<{ %struct.s }>))
declare i8* @llvm.stacksave()
declare void @llvm.stackrestore(i8*)
; 20 bytes of memory.
%struct.Args = type { i32, i32, i32, i32, i32 }
-declare dso_local x86_thiscallcc void @methodWithVtorDisp(i8* nocapture readonly, <{ %struct.Args }>* inalloca)
+declare dso_local x86_thiscallcc void @methodWithVtorDisp(i8* nocapture readonly, <{ %struct.Args }>* inalloca(<{ %struct.Args }>))
; Function Attrs: nounwind optsize
-define dso_local x86_thiscallcc void @methodWithVtorDisp_thunk(i8* %0, <{ %struct.Args }>* inalloca %1) #0 {
+define dso_local x86_thiscallcc void @methodWithVtorDisp_thunk(i8* %0, <{ %struct.Args }>* inalloca(<{ %struct.Args }>) %1) #0 {
; CHECK-LABEL: methodWithVtorDisp_thunk:
; CHECK: # %bb.0:
; CHECK-NEXT: pushl %esi
%7 = getelementptr i8, i8* %0, i32 %6
%8 = call i8* @llvm.returnaddress(i32 0)
call void @__cyg_profile_func_exit(i8* bitcast (void (i8*, <{ %struct.Args }>*)* @methodWithVtorDisp_thunk to i8*), i8* %8)
- musttail call x86_thiscallcc void @methodWithVtorDisp(i8* %7, <{ %struct.Args }>* inalloca nonnull %1)
+ musttail call x86_thiscallcc void @methodWithVtorDisp(i8* %7, <{ %struct.Args }>* inalloca(<{ %struct.Args }>) nonnull %1)
ret void
}
; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
; CHECK: jmpl
; CHECK-NOT: ret
-define x86_thiscallcc i32 @g_thunk(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca) {
+define x86_thiscallcc i32 @g_thunk(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca(<{ %struct.A, i32, %struct.A }>)) {
entry:
%1 = bitcast %struct.B* %this to i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)***
%vtable = load i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)**, i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)*** %1
%vfn = getelementptr inbounds i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)*, i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)** %vtable, i32 1
%2 = load i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)*, i32 (%struct.B*, <{ %struct.A, i32, %struct.A }>*)** %vfn
- %3 = musttail call x86_thiscallcc i32 %2(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca %0)
+ %3 = musttail call x86_thiscallcc i32 %2(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca(<{ %struct.A, i32, %struct.A }>) %0)
ret i32 %3
}
; CHECK: jmpl
; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
; CHECK-NOT: ret
-define x86_thiscallcc void @h_thunk(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca) {
+define x86_thiscallcc void @h_thunk(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca(<{ %struct.A, i32, %struct.A }>)) {
entry:
%1 = bitcast %struct.B* %this to void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)***
%vtable = load void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)**, void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)*** %1
%vfn = getelementptr inbounds void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)*, void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)** %vtable, i32 2
%2 = load void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)*, void (%struct.B*, <{ %struct.A, i32, %struct.A }>*)** %vfn
- musttail call x86_thiscallcc void %2(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca %0)
+ musttail call x86_thiscallcc void %2(%struct.B* %this, <{ %struct.A, i32, %struct.A }>* inalloca(<{ %struct.A, i32, %struct.A }>) %0)
ret void
}
; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
; CHECK: jmpl
; CHECK-NOT: ret
-define x86_thiscallcc %struct.A* @i_thunk(%struct.B* %this, <{ %struct.A*, %struct.A, i32, %struct.A }>* inalloca) {
+define x86_thiscallcc %struct.A* @i_thunk(%struct.B* %this, <{ %struct.A*, %struct.A, i32, %struct.A }>* inalloca(<{ %struct.A*, %struct.A, i32, %struct.A }>)) {
entry:
%1 = bitcast %struct.B* %this to %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)***
%vtable = load %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)**, %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)*** %1
%vfn = getelementptr inbounds %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)*, %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)** %vtable, i32 3
%2 = load %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)*, %struct.A* (%struct.B*, <{ %struct.A*, %struct.A, i32, %struct.A }>*)** %vfn
- %3 = musttail call x86_thiscallcc %struct.A* %2(%struct.B* %this, <{ %struct.A*, %struct.A, i32, %struct.A }>* inalloca %0)
+ %3 = musttail call x86_thiscallcc %struct.A* %2(%struct.B* %this, <{ %struct.A*, %struct.A, i32, %struct.A }>* inalloca(<{ %struct.A*, %struct.A, i32, %struct.A }>) %0)
ret %struct.A* %3
}
; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
; CHECK: jmpl
; CHECK-NOT: ret
-define x86_stdcallcc i32 @stdcall_thunk(<{ %struct.B*, %struct.A }>* inalloca) {
+define x86_stdcallcc i32 @stdcall_thunk(<{ %struct.B*, %struct.A }>* inalloca(<{ %struct.B*, %struct.A }>)) {
entry:
%this_ptr = getelementptr inbounds <{ %struct.B*, %struct.A }>, <{ %struct.B*, %struct.A }>* %0, i32 0, i32 0
%this = load %struct.B*, %struct.B** %this_ptr
%vtable = load i32 (<{ %struct.B*, %struct.A }>*)**, i32 (<{ %struct.B*, %struct.A }>*)*** %1
%vfn = getelementptr inbounds i32 (<{ %struct.B*, %struct.A }>*)*, i32 (<{ %struct.B*, %struct.A }>*)** %vtable, i32 1
%2 = load i32 (<{ %struct.B*, %struct.A }>*)*, i32 (<{ %struct.B*, %struct.A }>*)** %vfn
- %3 = musttail call x86_stdcallcc i32 %2(<{ %struct.B*, %struct.A }>* inalloca %0)
+ %3 = musttail call x86_stdcallcc i32 %2(<{ %struct.B*, %struct.A }>* inalloca(<{ %struct.B*, %struct.A }>) %0)
ret i32 %3
}
; CHECK-NOT: mov %{{.*}}, {{.*(.*esp.*)}}
; CHECK: jmpl
; CHECK-NOT: ret
-define x86_fastcallcc i32 @fastcall_thunk(%struct.B* inreg %this, <{ %struct.A }>* inalloca) {
+define x86_fastcallcc i32 @fastcall_thunk(%struct.B* inreg %this, <{ %struct.A }>* inalloca(<{ %struct.A }>)) {
entry:
%1 = bitcast %struct.B* %this to i32 (%struct.B*, <{ %struct.A }>*)***
%vtable = load i32 (%struct.B*, <{ %struct.A }>*)**, i32 (%struct.B*, <{ %struct.A }>*)*** %1
%vfn = getelementptr inbounds i32 (%struct.B*, <{ %struct.A }>*)*, i32 (%struct.B*, <{ %struct.A }>*)** %vtable, i32 1
%2 = load i32 (%struct.B*, <{ %struct.A }>*)*, i32 (%struct.B*, <{ %struct.A }>*)** %vfn
- %3 = musttail call x86_fastcallcc i32 %2(%struct.B* inreg %this, <{ %struct.A }>* inalloca %0)
+ %3 = musttail call x86_fastcallcc i32 %2(%struct.B* inreg %this, <{ %struct.A }>* inalloca(<{ %struct.A }>) %0)
ret i32 %3
}
; CHECK-LABEL: t3:
; CHECK: jmp {{_?}}t3_callee
-define x86_thiscallcc i8* @t3(i8* %this, <{ i8*, i32 }>* inalloca %args) {
+define x86_thiscallcc i8* @t3(i8* %this, <{ i8*, i32 }>* inalloca(<{ i8*, i32 }>) %args) {
%adj = getelementptr i8, i8* %this, i32 4
%a_ptr = getelementptr <{ i8*, i32 }>, <{ i8*, i32 }>* %args, i32 0, i32 1
store i32 0, i32* %a_ptr
- %rv = musttail call x86_thiscallcc i8* @t3_callee(i8* %adj, <{ i8*, i32 }>* inalloca %args)
+ %rv = musttail call x86_thiscallcc i8* @t3_callee(i8* %adj, <{ i8*, i32 }>* inalloca(<{ i8*, i32 }>) %args)
ret i8* %rv
}
-declare x86_thiscallcc i8* @t3_callee(i8* %this, <{ i8*, i32 }>* inalloca %args);
+declare x86_thiscallcc i8* @t3_callee(i8* %this, <{ i8*, i32 }>* inalloca(<{ i8*, i32 }>) %args);
; CHECK-LABEL: t4:
; CHECK: jmp {{_?}}t4_callee
br label %bb2
bb2:
- call void @inalloca_params(<{ %struct.S }>* inalloca nonnull %argmem)
+ call void @inalloca_params(<{ %struct.S }>* inalloca(<{ %struct.S }>) nonnull %argmem)
ret void
}
; CHECK: popl %ebp
; CHECK: retl
-declare void @inalloca_params(<{ %struct.S }>* inalloca)
+declare void @inalloca_params(<{ %struct.S }>* inalloca(<{ %struct.S }>))
declare i32 @doSomething(i32, i32*)
; CHECK: calll _tail_std@4
; CHECK: retl $4
-define x86_thiscallcc void @inalloca(i32* %this, i32* inalloca %args) {
+define x86_thiscallcc void @inalloca(i32* %this, i32* inalloca(i32) %args) {
entry:
%val = load i32, i32* %args
store i32 0, i32* %args
%struct.T = type { i64, [3 x i32] }
; Function Attrs: nounwind optsize
-define void @f(i8* %p, i8* %q, i32* inalloca nocapture %unused) #0 {
+define void @f(i8* %p, i8* %q, i32* inalloca(i32) nocapture %unused) #0 {
entry:
%g = alloca %struct.T, align 8
%r = alloca i32, align 8
ret void
}
-define void @f_pgso(i8* %p, i8* %q, i32* inalloca nocapture %unused) !prof !14 {
+define void @f_pgso(i8* %p, i8* %q, i32* inalloca(i32) nocapture %unused) !prof !14 {
entry:
%g = alloca %struct.T, align 8
%r = alloca i32, align 8
%struct.NonTrivial = type { i32 }
; Function Attrs: nounwind
-define void @f(<{ %struct.NonTrivial, i32, i32, i32 }>* inalloca) local_unnamed_addr #0 !dbg !7 {
+define void @f(<{ %struct.NonTrivial, i32, i32, i32 }>* inalloca(<{ %struct.NonTrivial, i32, i32, i32 }>)) local_unnamed_addr #0 !dbg !7 {
entry:
%a = getelementptr inbounds <{ %struct.NonTrivial, i32, i32, i32 }>, <{ %struct.NonTrivial, i32, i32, i32 }>* %0, i32 0, i32 0
%b = getelementptr inbounds <{ %struct.NonTrivial, i32, i32, i32 }>, <{ %struct.NonTrivial, i32, i32, i32 }>* %0, i32 0, i32 1
entry:
%t = alloca inalloca i32
store i32 42, i32* %t
- call void @pass_inalloca(i32* inalloca %t)
+ call void @pass_inalloca(i32* inalloca(i32) %t)
ret void
}
-declare void @pass_inalloca(i32* inalloca)
+declare void @pass_inalloca(i32* inalloca(i32))
--- /dev/null
+%a = type { i64 }
+%struct = type { i32, i8 }
+
+define void @g(%a* inalloca(%a)) {
+ ret void
+}
+
+declare void @baz(%struct* inalloca(%struct))
+
+define void @foo(%struct* inalloca(%struct) %a) {
+ call void @baz(%struct* inalloca(%struct) %a)
+ ret void
+}
--- /dev/null
+; RUN: llvm-link %s %p/Inputs/inalloca-type-input.ll -S | FileCheck %s
+
+%a = type { i64 }
+%struct = type { i32, i8 }
+
+; CHECK-LABEL: define void @f(%a* inalloca(%a) %0)
+define void @f(%a* inalloca(%a)) {
+ ret void
+}
+
+; CHECK-LABEL: define void @bar(
+; CHECK: call void @foo(%struct* inalloca(%struct) %ptr)
+define void @bar() {
+ %ptr = alloca inalloca %struct
+ call void @foo(%struct* inalloca(%struct) %ptr)
+ ret void
+}
+
+; CHECK-LABEL: define void @g(%a* inalloca(%a) %0)
+
+; CHECK-LABEL: define void @foo(%struct* inalloca(%struct) %a)
+; CHECK-NEXT: call void @baz(%struct* inalloca(%struct) %a)
+declare void @foo(%struct* inalloca(%struct) %a)
+
+; CHECK: declare void @baz(%struct* inalloca(%struct))
%struct.a = type { i8 }
-define internal x86_thiscallcc void @internalfun(%struct.a* %this, <{ %struct.a }>* inalloca) {
+define internal x86_thiscallcc void @internalfun(%struct.a* %this, <{ %struct.a }>* inalloca(<{ %struct.a }>)) {
; ARGPROMOTION-LABEL: define {{[^@]+}}@internalfun
-; ARGPROMOTION-SAME: (%struct.a* [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* inalloca [[TMP0:%.*]])
+; ARGPROMOTION-SAME: (%struct.a* [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* inalloca(<{ [[STRUCT_A]] }>) [[TMP0:%.*]]) {
; ARGPROMOTION-NEXT: entry:
; ARGPROMOTION-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0
; ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4
; ARGPROMOTION-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0
; ARGPROMOTION-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* [[TMP1]], %struct.a* dereferenceable(1) [[A]])
-; ARGPROMOTION-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca [[ARGMEM]])
+; ARGPROMOTION-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca(<{ [[STRUCT_A]] }>) [[ARGMEM]])
; ARGPROMOTION-NEXT: ret void
;
; GLOBALOPT_ARGPROMOTION-LABEL: define {{[^@]+}}@internalfun
-; GLOBALOPT_ARGPROMOTION-SAME: (<{ [[STRUCT_A:%.*]] }>* [[TMP0:%.*]]) unnamed_addr
+; GLOBALOPT_ARGPROMOTION-SAME: (<{ [[STRUCT_A:%.*]] }>* [[TMP0:%.*]]) unnamed_addr {
; GLOBALOPT_ARGPROMOTION-NEXT: entry:
; GLOBALOPT_ARGPROMOTION-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0
; GLOBALOPT_ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4
; GLOBALOPT_ARGPROMOTION-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0
; GLOBALOPT_ARGPROMOTION-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* [[TMP1]], %struct.a* dereferenceable(1) [[A]])
-; GLOBALOPT_ARGPROMOTION-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca [[ARGMEM]])
+; GLOBALOPT_ARGPROMOTION-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca(<{ [[STRUCT_A]] }>) [[ARGMEM]])
; GLOBALOPT_ARGPROMOTION-NEXT: ret void
;
entry:
%argmem = alloca inalloca <{ %struct.a }>, align 4
%1 = getelementptr inbounds <{ %struct.a }>, <{ %struct.a }>* %argmem, i32 0, i32 0
%call = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* %1, %struct.a* dereferenceable(1) %a)
- call void @ext(<{ %struct.a }>* inalloca %argmem)
+ call void @ext(<{ %struct.a }>* inalloca(<{ %struct.a }>) %argmem)
ret void
}
; This is here to ensure @internalfun is live.
define void @exportedfun(%struct.a* %a) {
; ARGPROMOTION-LABEL: define {{[^@]+}}@exportedfun
-; ARGPROMOTION-SAME: (%struct.a* [[A:%.*]])
+; ARGPROMOTION-SAME: (%struct.a* [[A:%.*]]) {
; ARGPROMOTION-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave()
; ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4
-; ARGPROMOTION-NEXT: call x86_thiscallcc void @internalfun(%struct.a* [[A]], <{ [[STRUCT_A]] }>* inalloca [[ARGMEM]])
+; ARGPROMOTION-NEXT: call x86_thiscallcc void @internalfun(%struct.a* [[A]], <{ [[STRUCT_A]] }>* inalloca(<{ [[STRUCT_A]] }>) [[ARGMEM]])
; ARGPROMOTION-NEXT: call void @llvm.stackrestore(i8* [[INALLOCA_SAVE]])
; ARGPROMOTION-NEXT: ret void
;
; GLOBALOPT_ARGPROMOTION-LABEL: define {{[^@]+}}@exportedfun
-; GLOBALOPT_ARGPROMOTION-SAME: (%struct.a* [[A:%.*]]) local_unnamed_addr
+; GLOBALOPT_ARGPROMOTION-SAME: (%struct.a* [[A:%.*]]) local_unnamed_addr {
; GLOBALOPT_ARGPROMOTION-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave()
; GLOBALOPT_ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4
; GLOBALOPT_ARGPROMOTION-NEXT: call fastcc void @internalfun(<{ [[STRUCT_A]] }>* [[ARGMEM]])
;
%inalloca.save = tail call i8* @llvm.stacksave()
%argmem = alloca inalloca <{ %struct.a }>, align 4
- call x86_thiscallcc void @internalfun(%struct.a* %a, <{ %struct.a }>* inalloca %argmem)
+ call x86_thiscallcc void @internalfun(%struct.a* %a, <{ %struct.a }>* inalloca(<{ %struct.a }>) %argmem)
call void @llvm.stackrestore(i8* %inalloca.save)
ret void
}
declare x86_thiscallcc %struct.a* @copy_ctor(%struct.a* returned, %struct.a* dereferenceable(1))
-declare void @ext(<{ %struct.a }>* inalloca)
+declare void @ext(<{ %struct.a }>* inalloca(<{ %struct.a }>))
declare i8* @llvm.stacksave()
declare void @llvm.stackrestore(i8*)
%struct.ss = type { i32, i32 }
; Argpromote + sroa should change this to passing the two integers by value.
-define internal i32 @f(%struct.ss* inalloca %s) {
+define internal i32 @f(%struct.ss* inalloca(%struct.ss) %s) {
; CHECK-LABEL: define {{[^@]+}}@f
-; CHECK-SAME: (i32 [[S_0_0_VAL:%.*]], i32 [[S_0_1_VAL:%.*]]) unnamed_addr
+; CHECK-SAME: (i32 [[S_0_0_VAL:%.*]], i32 [[S_0_1_VAL:%.*]]) unnamed_addr {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[R:%.*]] = add i32 [[S_0_0_VAL]], [[S_0_1_VAL]]
; CHECK-NEXT: ret i32 [[R]]
}
define i32 @main() {
-; CHECK-LABEL: define {{[^@]+}}@main() local_unnamed_addr
+; CHECK-LABEL: define {{[^@]+}}@main() local_unnamed_addr {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[R:%.*]] = call fastcc i32 @f(i32 1, i32 2)
; CHECK-NEXT: ret i32 [[R]]
%f1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 1
store i32 1, i32* %f0, align 4
store i32 2, i32* %f1, align 4
- %r = call i32 @f(%struct.ss* inalloca %S)
+ %r = call i32 @f(%struct.ss* inalloca(%struct.ss) %S)
ret i32 %r
}
; Argpromote can't promote %a because of the icmp use.
-define internal i1 @g(%struct.ss* %a, %struct.ss* inalloca %b) nounwind {
+define internal i1 @g(%struct.ss* %a, %struct.ss* inalloca(%struct.ss) %b) nounwind {
; CHECK-LABEL: define {{[^@]+}}@g
-; CHECK-SAME: (%struct.ss* [[A:%.*]], %struct.ss* [[B:%.*]]) unnamed_addr
+; CHECK-SAME: (%struct.ss* [[A:%.*]], %struct.ss* [[B:%.*]]) unnamed_addr #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C:%.*]] = icmp eq %struct.ss* [[A]], [[B]]
; CHECK-NEXT: ret i1 [[C]]
}
define i32 @test() {
-; CHECK-LABEL: define {{[^@]+}}@test() local_unnamed_addr
+; CHECK-LABEL: define {{[^@]+}}@test() local_unnamed_addr {
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[S:%.*]] = alloca inalloca [[STRUCT_SS:%.*]]
+; CHECK-NEXT: [[S:%.*]] = alloca inalloca [[STRUCT_SS:%.*]], align 4
; CHECK-NEXT: [[C:%.*]] = call fastcc i1 @g(%struct.ss* [[S]], %struct.ss* [[S]])
; CHECK-NEXT: ret i32 0
;
entry:
%S = alloca inalloca %struct.ss
- %c = call i1 @g(%struct.ss* %S, %struct.ss* inalloca %S)
+ %c = call i1 @g(%struct.ss* %S, %struct.ss* inalloca(%struct.ss) %S)
ret i32 0
}
%struct.a = type { i8 }
-define internal x86_thiscallcc void @internalfun(%struct.a* %this, <{ %struct.a }>* inalloca) {
+define internal x86_thiscallcc void @internalfun(%struct.a* %this, <{ %struct.a }>* inalloca(<{ %struct.a }>)) {
; CHECK-LABEL: define {{[^@]+}}@internalfun
-; CHECK-SAME: (%struct.a* noalias nocapture nofree readnone [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* inalloca noundef nonnull align 4 dereferenceable(1) [[TMP0:%.*]]) {
+; CHECK-SAME: (%struct.a* noalias nocapture nofree readnone [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* noundef nonnull inalloca(<{ [[STRUCT_A]] }>) align 4 dereferenceable(1) [[TMP0:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0
; CHECK-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0
; CHECK-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* noundef nonnull align 4 dereferenceable(1) [[TMP1]], %struct.a* noundef nonnull align 4 dereferenceable(1) [[A]])
-; CHECK-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca noundef nonnull align 4 dereferenceable(1) [[ARGMEM]])
+; CHECK-NEXT: call void @ext(<{ [[STRUCT_A]] }>* noundef nonnull inalloca(<{ [[STRUCT_A]] }>) align 4 dereferenceable(1) [[ARGMEM]])
; CHECK-NEXT: ret void
;
entry:
%argmem = alloca inalloca <{ %struct.a }>, align 4
%1 = getelementptr inbounds <{ %struct.a }>, <{ %struct.a }>* %argmem, i32 0, i32 0
%call = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* %1, %struct.a* dereferenceable(1) %a)
- call void @ext(<{ %struct.a }>* inalloca %argmem)
+ call void @ext(<{ %struct.a }>* inalloca(<{ %struct.a }>) %argmem)
ret void
}
; CHECK-SAME: (%struct.a* nocapture nofree readnone [[A:%.*]]) {
; CHECK-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave() #[[ATTR1:[0-9]+]]
; CHECK-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4
-; CHECK-NEXT: call x86_thiscallcc void @internalfun(%struct.a* noalias nocapture nofree readnone undef, <{ [[STRUCT_A]] }>* inalloca noundef nonnull align 4 dereferenceable(1) [[ARGMEM]])
+; CHECK-NEXT: call x86_thiscallcc void @internalfun(%struct.a* noalias nocapture nofree readnone undef, <{ [[STRUCT_A]] }>* noundef nonnull inalloca(<{ [[STRUCT_A]] }>) align 4 dereferenceable(1) [[ARGMEM]])
; CHECK-NEXT: call void @llvm.stackrestore(i8* nofree [[INALLOCA_SAVE]])
; CHECK-NEXT: ret void
;
%inalloca.save = tail call i8* @llvm.stacksave()
%argmem = alloca inalloca <{ %struct.a }>, align 4
- call x86_thiscallcc void @internalfun(%struct.a* %a, <{ %struct.a }>* inalloca %argmem)
+ call x86_thiscallcc void @internalfun(%struct.a* %a, <{ %struct.a }>* inalloca(<{ %struct.a }>) %argmem)
call void @llvm.stackrestore(i8* %inalloca.save)
ret void
}
declare x86_thiscallcc %struct.a* @copy_ctor(%struct.a* returned, %struct.a* dereferenceable(1))
-declare void @ext(<{ %struct.a }>* inalloca)
+declare void @ext(<{ %struct.a }>* inalloca(<{ %struct.a }>))
declare i8* @llvm.stacksave()
declare void @llvm.stackrestore(i8*)
;.
%struct.ss = type { i32, i32 }
; Argpromote + sroa should change this to passing the two integers by value.
-define internal i32 @f(%struct.ss* inalloca %s) {
+define internal i32 @f(%struct.ss* inalloca(%struct.ss) %s) {
; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind readonly willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@f
-; IS__TUNIT____-SAME: (%struct.ss* inalloca noalias nocapture nofree noundef nonnull align 4 dereferenceable(8) [[S:%.*]]) #[[ATTR0:[0-9]+]] {
+; IS__TUNIT____-SAME: (%struct.ss* noalias nocapture nofree noundef nonnull inalloca([[STRUCT_SS:%.*]]) align 4 dereferenceable(8) [[S:%.*]]) #[[ATTR0:[0-9]+]] {
; IS__TUNIT____-NEXT: entry:
-; IS__TUNIT____-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[S]], i32 0, i32 0
+; IS__TUNIT____-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__TUNIT____-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__TUNIT____-NEXT: [[A:%.*]] = load i32, i32* [[F0]], align 4
; IS__TUNIT____-NEXT: [[B:%.*]] = load i32, i32* [[F1]], align 4
;
; IS__CGSCC____: Function Attrs: argmemonly nofree norecurse nosync nounwind readonly willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@f
-; IS__CGSCC____-SAME: (%struct.ss* inalloca noalias nocapture nofree noundef nonnull align 4 dereferenceable(8) [[S:%.*]]) #[[ATTR0:[0-9]+]] {
+; IS__CGSCC____-SAME: (%struct.ss* noalias nocapture nofree noundef nonnull inalloca([[STRUCT_SS:%.*]]) align 4 dereferenceable(8) [[S:%.*]]) #[[ATTR0:[0-9]+]] {
; IS__CGSCC____-NEXT: entry:
-; IS__CGSCC____-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[S]], i32 0, i32 0
+; IS__CGSCC____-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
; IS__CGSCC____-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC____-NEXT: [[A:%.*]] = load i32, i32* [[F0]], align 4
; IS__CGSCC____-NEXT: [[B:%.*]] = load i32, i32* [[F1]], align 4
; IS__TUNIT____-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__TUNIT____-NEXT: store i32 1, i32* [[F0]], align 4
; IS__TUNIT____-NEXT: store i32 2, i32* [[F1]], align 4
-; IS__TUNIT____-NEXT: [[R:%.*]] = call i32 @f(%struct.ss* inalloca noalias nocapture nofree noundef nonnull align 4 dereferenceable(8) [[S]]) #[[ATTR2:[0-9]+]]
+; IS__TUNIT____-NEXT: [[R:%.*]] = call i32 @f(%struct.ss* noalias nocapture nofree noundef nonnull inalloca([[STRUCT_SS]]) align 4 dereferenceable(8) [[S]]) #[[ATTR2:[0-9]+]]
; IS__TUNIT____-NEXT: ret i32 [[R]]
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
; IS__CGSCC____-NEXT: store i32 1, i32* [[F0]], align 4
; IS__CGSCC____-NEXT: store i32 2, i32* [[F1]], align 4
-; IS__CGSCC____-NEXT: [[R:%.*]] = call i32 @f(%struct.ss* inalloca noalias nocapture nofree noundef nonnull align 4 dereferenceable(8) [[S]]) #[[ATTR2:[0-9]+]]
+; IS__CGSCC____-NEXT: [[R:%.*]] = call i32 @f(%struct.ss* noalias nocapture nofree noundef nonnull inalloca([[STRUCT_SS]]) align 4 dereferenceable(8) [[S]]) #[[ATTR2:[0-9]+]]
; IS__CGSCC____-NEXT: ret i32 [[R]]
;
entry:
%f1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 1
store i32 1, i32* %f0, align 4
store i32 2, i32* %f1, align 4
- %r = call i32 @f(%struct.ss* inalloca %S)
+ %r = call i32 @f(%struct.ss* inalloca(%struct.ss) %S)
ret i32 %r
}
; Argpromote can't promote %a because of the icmp use.
-define internal i1 @g(%struct.ss* %a, %struct.ss* inalloca %b) nounwind {
+define internal i1 @g(%struct.ss* %a, %struct.ss* inalloca(%struct.ss) %b) nounwind {
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@g
-; IS__CGSCC____-SAME: (%struct.ss* noalias nocapture nofree nonnull readnone align 4 dereferenceable(8) [[A:%.*]], %struct.ss* inalloca noalias nocapture nofree nonnull writeonly align 4 dereferenceable(8) [[B:%.*]]) #[[ATTR1]] {
+; IS__CGSCC____-SAME: (%struct.ss* noalias nocapture nofree nonnull readnone align 4 dereferenceable(8) [[A:%.*]], %struct.ss* noalias nocapture nofree nonnull writeonly inalloca([[STRUCT_SS:%.*]]) align 4 dereferenceable(8) [[B:%.*]]) #[[ATTR1]] {
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: ret i1 undef
;
;
entry:
%S = alloca inalloca %struct.ss
- %c = call i1 @g(%struct.ss* %S, %struct.ss* inalloca %S)
+ %c = call i1 @g(%struct.ss* %S, %struct.ss* inalloca(%struct.ss) %S)
ret i32 0
}
;.
}
; inalloca parameters are always considered written
-define void @test7_1(i32* inalloca %a) {
+define void @test7_1(i32* inalloca(i32) %a) {
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@test7_1
-; IS__TUNIT____-SAME: (i32* inalloca nocapture nofree nonnull writeonly dereferenceable(4) [[A:%.*]]) #[[ATTR1]] {
+; IS__TUNIT____-SAME: (i32* nocapture nofree nonnull writeonly inalloca(i32) dereferenceable(4) [[A:%.*]]) #[[ATTR1]] {
; IS__TUNIT____-NEXT: ret void
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@test7_1
-; IS__CGSCC____-SAME: (i32* inalloca nocapture nofree nonnull writeonly dereferenceable(4) [[A:%.*]]) #[[ATTR1]] {
+; IS__CGSCC____-SAME: (i32* nocapture nofree nonnull writeonly inalloca(i32) dereferenceable(4) [[A:%.*]]) #[[ATTR1]] {
; IS__CGSCC____-NEXT: ret void
;
ret void
; Do not touch complicated arguments (for now)
%struct.X = type { i8* }
-define internal i32* @test_inalloca(i32* inalloca %a) {
+define internal i32* @test_inalloca(i32* inalloca(i32) %a) {
; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@test_inalloca
-; IS__TUNIT____-SAME: (i32* inalloca noalias nofree nonnull returned writeonly dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
+; IS__TUNIT____-SAME: (i32* noalias nofree nonnull returned writeonly inalloca(i32) dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
; IS__TUNIT____-NEXT: ret i32* [[A]]
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@test_inalloca
-; IS__CGSCC____-SAME: (i32* inalloca noalias nofree noundef nonnull returned writeonly dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
+; IS__CGSCC____-SAME: (i32* noalias nofree noundef nonnull returned writeonly inalloca(i32) dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
; IS__CGSCC____-NEXT: ret i32* [[A]]
;
ret i32* %a
; We can't remove 'this' here, as that would put argmem in ecx instead of
; memory.
-define internal x86_thiscallcc i32 @unused_this(i32* %this, i32* inalloca %argmem) {
+define internal x86_thiscallcc i32 @unused_this(i32* %this, i32* inalloca(i32) %argmem) {
;
;
%v = load i32, i32* %argmem
ret i32 %v
}
-; CHECK-LABEL: define internal x86_thiscallcc i32 @unused_this(i32* %this, i32* inalloca %argmem)
+; CHECK-LABEL: define internal x86_thiscallcc i32 @unused_this(i32* %this, i32* inalloca(i32) %argmem)
define i32 @caller2() {
;
%t = alloca i32
%m = alloca inalloca i32
store i32 42, i32* %m
- %v = call x86_thiscallcc i32 @unused_this(i32* %t, i32* inalloca %m)
+ %v = call x86_thiscallcc i32 @unused_this(i32* %t, i32* inalloca(i32) %m)
ret i32 %v
}
}
; Test for inalloca handling.
-define void @test9_2(%struct.x* inalloca %a) nounwind {
+define void @test9_2(%struct.x* inalloca(%struct.x) %a) nounwind {
; CHECK-LABEL: @test9_2(
; CHECK-NEXT: ret void
;
ret void
}
-; CHECK: define void @test7_1(i32* inalloca nocapture %a)
+; CHECK: define void @test7_1(i32* nocapture inalloca(i32) %a)
; inalloca parameters are always considered written
-define void @test7_1(i32* inalloca %a) {
+define void @test7_1(i32* inalloca(i32) %a) {
ret void
}
%struct.S = type { i8* }
-declare void @f(<{ %struct.S }>* inalloca)
+declare void @f(<{ %struct.S }>* inalloca(<{ %struct.S }>))
; Check that we don't clone the %x alloca and insert it in the live range of
br label %exit
exit:
- call void @f(<{ %struct.S }>* inalloca %argmem)
+ call void @f(<{ %struct.S }>* inalloca(<{ %struct.S }>) %argmem)
call void @llvm.stackrestore(i8* %inalloca.save)
ret void
}
ret i32 %v
}
-define internal i32 @inalloca(i32* inalloca %p) {
+define internal i32 @inalloca(i32* inalloca(i32) %p) {
; CHECK-LABEL: define internal fastcc i32 @inalloca(i32* %p)
%rv = load i32, i32* %p
ret i32 %rv
}
-define i32 @inalloca2_caller(i32* inalloca %p) {
- %rv = musttail call i32 @inalloca2(i32* inalloca %p)
+define i32 @inalloca2_caller(i32* inalloca(i32) %p) {
+ %rv = musttail call i32 @inalloca2(i32* inalloca(i32) %p)
ret i32 %rv
}
-define internal i32 @inalloca2(i32* inalloca %p) {
+define internal i32 @inalloca2(i32* inalloca(i32) %p) {
; Because of the musttail caller, this inalloca cannot be dropped.
-; CHECK-LABEL: define internal i32 @inalloca2(i32* inalloca %p)
+; CHECK-LABEL: define internal i32 @inalloca2(i32* inalloca(i32) %p)
%rv = load i32, i32* %p
ret i32 %rv
}
call coldcc i32 @h(i32* %m)
call i32 @j(i32* %m)
%args = alloca inalloca i32
- call i32 @inalloca(i32* inalloca %args)
+ call i32 @inalloca(i32* inalloca(i32) %args)
%c = call token @llvm.call.preallocated.setup(i32 1)
%N = call i8* @llvm.call.preallocated.arg(token %c, i32 0) preallocated(i32)
%n = bitcast i8* %N to i32*
%argmem = alloca inalloca <{ %struct.Foo }>, align 4
%0 = getelementptr inbounds <{ %struct.Foo }>, <{ %struct.Foo }>* %argmem, i32 0, i32 0
%call = call x86_thiscallcc %struct.Foo* @"\01??0Foo@@QAE@XZ"(%struct.Foo* %0)
- call void @h(<{ %struct.Foo }>* inalloca %argmem)
+ call void @h(<{ %struct.Foo }>* inalloca(<{ %struct.Foo }>) %argmem)
call void @llvm.stackrestore(i8* %inalloca.save)
ret void
}
; Function Attrs: alwaysinline inlinehint nounwind
-define internal void @h(<{ %struct.Foo }>* inalloca) alwaysinline {
+define internal void @h(<{ %struct.Foo }>* inalloca(<{ %struct.Foo }>)) alwaysinline {
entry:
%o = getelementptr inbounds <{ %struct.Foo }>, <{ %struct.Foo }>* %0, i32 0, i32 0
call x86_thiscallcc void @"\01??1Foo@@QAE@XZ"(%struct.Foo* %o)
; PR19569
%struct_type = type { i32, i32 }
-declare void @test9_aux(<{ %struct_type }>* inalloca)
+declare void @test9_aux(<{ %struct_type }>* inalloca(<{ %struct_type }>))
declare i8* @llvm.stacksave()
declare void @llvm.stackrestore(i8*)
; ALL-NEXT: [[TMP0:%.*]] = bitcast %struct_type* [[A:%.*]] to i64*
; ALL-NEXT: [[TMP1:%.*]] = load i64, i64* [[TMP0]], align 4
; ALL-NEXT: store i64 [[TMP1]], i64* [[ARGMEM]], align 8
-; ALL-NEXT: call void @test9_aux(<{ [[STRUCT_TYPE]] }>* inalloca nonnull [[TMPCAST]])
+; ALL-NEXT: call void @test9_aux(<{ [[STRUCT_TYPE]] }>* nonnull inalloca(<{ [[STRUCT_TYPE]] }>) [[TMPCAST]])
; ALL-NEXT: ret void
;
entry:
%1 = bitcast %struct_type* %0 to i8*
%2 = bitcast %struct_type* %a to i8*
call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %1, i8* align 4 %2, i32 8, i1 false)
- call void @test9_aux(<{ %struct_type }>* inalloca %argmem)
+ call void @test9_aux(<{ %struct_type }>* inalloca(<{ %struct_type }>) %argmem)
call void @llvm.stackrestore(i8* %inalloca.save)
ret void
}
target triple = "i686-pc-linux-gnu"
declare void @takes_i32(i32)
-declare void @takes_i32_inalloca(i32* inalloca)
+declare void @takes_i32_inalloca(i32* inalloca(i32))
define void @f() {
; CHECK-LABEL: define void @f()
%args = alloca inalloca i32
- call void bitcast (void (i32)* @takes_i32 to void (i32*)*)(i32* inalloca %args)
+ call void bitcast (void (i32)* @takes_i32 to void (i32*)*)(i32* inalloca(i32) %args)
; CHECK: call void bitcast
ret void
}
define i32* @test1(i32 %P) {
%tmp = call i8* @llvm.stacksave( )
call void @llvm.stackrestore( i8* %tmp ) ;; not restoring anything
- %A = alloca i32, i32 %P
+ %A = alloca i32, i32 %P
ret i32* %A
}
%tmp77 = alloca i8, i32 %size ; <i8*> [#uses=1]
%tmp78 = call i8* @llvm.stacksave( ) ; <i8*> [#uses=1]
%tmp102 = alloca i8, i32 %size ; <i8*> [#uses=1]
- call void @bar( i32 %i.0.reg2mem.0, i8* %tmp23, i8* %tmp52, i8* %tmp77, i8* %tmp102, i32 %size ) nounwind
+ call void @bar( i32 %i.0.reg2mem.0, i8* %tmp23, i8* %tmp52, i8* %tmp77, i8* %tmp102, i32 %size ) nounwind
call void @llvm.stackrestore( i8* %tmp78 )
call void @llvm.stackrestore( i8* %tmp53 )
call void @llvm.stackrestore( i8* %tmp28 )
declare void @bar(i32, i8*, i8*, i8*, i8*, i32)
-declare void @inalloca_callee(i32* inalloca)
+declare void @inalloca_callee(i32* inalloca(i32))
define void @test3(i32 %c) {
entry:
%save1 = call i8* @llvm.stacksave()
%argmem = alloca inalloca i32
store i32 0, i32* %argmem
- call void @inalloca_callee(i32* inalloca %argmem)
+ call void @inalloca_callee(i32* inalloca(i32) %argmem)
; This restore cannot be deleted, the restore below does not make it dead.
call void @llvm.stackrestore(i8* %save1)
; CHECK: %save1 = call i8* @llvm.stacksave()
; CHECK: %argmem = alloca inalloca i32
; CHECK: store i32 0, i32* %argmem
-; CHECK: call void @inalloca_callee(i32* inalloca {{.*}} %argmem)
+; CHECK: call void @inalloca_callee(i32* {{.*}} inalloca(i32) %argmem)
; CHECK: call void @llvm.stackrestore(i8* %save1)
; CHECK: br i1 %done, label %loop, label %return
; CHECK: ret void
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
-; CHECK: Wrong types for attribute: inalloca nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) preallocated(i32) sret(i32) align 1 dereferenceable(1) dereferenceable_or_null(1)
+; CHECK: Wrong types for attribute: nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) inalloca(i32) preallocated(i32) sret(i32) align 1 dereferenceable(1) dereferenceable_or_null(1)
; CHECK-NEXT: @align_non_pointer1
define void @align_non_pointer1(i32 align 4 %a) {
ret void
}
-; CHECK: Wrong types for attribute: inalloca nest noalias nocapture noundef nonnull readnone readonly signext zeroext byref(void) byval(void) preallocated(void) sret(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
+; CHECK: Wrong types for attribute: nest noalias nocapture noundef nonnull readnone readonly signext zeroext byref(void) byval(void) inalloca(void) preallocated(void) sret(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
; CHECK-NEXT: @align_non_pointer2
define align 4 void @align_non_pointer2(i32 %a) {
ret void
; CHECK: Calling convention disallows inalloca
; CHECK-NEXT: void (i32*)* @inalloca_as0_cc_amdgpu_kernel
-define amdgpu_kernel void @inalloca_as0_cc_amdgpu_kernel(i32* inalloca %ptr) {
+define amdgpu_kernel void @inalloca_as0_cc_amdgpu_kernel(i32* inalloca(i32) %ptr) {
ret void
}
; CHECK: Attributes 'byval', 'inalloca', 'preallocated', 'inreg', 'nest', 'byref', and 'sret' are incompatible!
; CHECK-NEXT: void (i32*)* @byref_inalloca
-define void @byref_inalloca(i32* byref(i32) inalloca) {
+define void @byref_inalloca(i32* byref(i32) inalloca(i32)) {
ret void
}
ret void
}
-; CHECK: Wrong types for attribute: inalloca nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) preallocated(i32) sret(i32) align 1 dereferenceable(1) dereferenceable_or_null(1)
+; CHECK: Wrong types for attribute: nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) inalloca(i32) preallocated(i32) sret(i32) align 1 dereferenceable(1) dereferenceable_or_null(1)
; CHECK-NEXT: void (i32)* @byref_non_pointer
define void @byref_non_pointer(i32 byref(i32)) {
ret void
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
-; CHECK: Wrong types for attribute: inalloca nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) preallocated(i32) sret(i32) align 1 dereferenceable(1) dereferenceable_or_null(1)
+; CHECK: Wrong types for attribute: nest noalias nocapture nonnull readnone readonly byref(i32) byval(i32) inalloca(i32) preallocated(i32) sret(i32) align 1 dereferenceable(1) dereferenceable_or_null(1)
; CHECK-NEXT: void (i32)* @h
declare void @h(i32 byval(i32) %num)
declare void @h(i32, ...)
define void @i() {
%args = alloca inalloca i32
- call void (i32, ...) @h(i32 1, i32* inalloca %args, i32 3)
+ call void (i32, ...) @h(i32 1, i32* inalloca(i32) %args, i32 3)
; CHECK: inalloca isn't on the last argument!
ret void
}
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
-declare void @a(i64* byval(i64) inalloca %p)
+declare void @a(i64* byval(i64) inalloca(i64) %p)
; CHECK: Attributes {{.*}} are incompatible
-declare void @b(i64* inreg inalloca %p)
+declare void @b(i64* inreg inalloca(i64) %p)
; CHECK: Attributes {{.*}} are incompatible
-declare void @c(i64* sret(i64) inalloca %p)
+declare void @c(i64* sret(i64) inalloca(i64) %p)
; CHECK: Attributes {{.*}} are incompatible
-declare void @d(i64* nest inalloca %p)
+declare void @d(i64* nest inalloca(i64) %p)
; CHECK: Attributes {{.*}} are incompatible
-declare void @e(i64* readonly inalloca %p)
+declare void @e(i64* readonly inalloca(i64) %p)
; CHECK: Attributes {{.*}} are incompatible
-declare void @f(void ()* inalloca %p)
+declare void @f(void ()* inalloca(void()) %p)
; CHECK: do not support unsized types
-declare void @g(i32* inalloca %p, i32 %p2)
+declare void @g(i32* inalloca(i32) %p, i32 %p2)
; CHECK: inalloca isn't on the last parameter!
+
+; CHECK: Attribute 'inalloca' type does not match parameter!
+; CHECK-NEXT: void (i32*)* @inalloca_mismatched_pointee_type0
+define void @inalloca_mismatched_pointee_type0(i32* inalloca(i8)) {
+ ret void
+}
+
+; CHECK: Wrong types for attribute:
+; CHECK-NEXT: void (i8)* @inalloca_not_pointer
+define void @inalloca_not_pointer(i8 byref(i8)) {
+ ret void
+}
; doesn't reject it.
; RUN: llvm-as %s -o /dev/null
-declare void @doit(i64* inalloca %a)
+declare void @doit(i64* inalloca(i64) %a)
define void @a() {
entry:
%a = alloca inalloca [2 x i32]
%b = bitcast [2 x i32]* %a to i64*
- call void @doit(i64* inalloca %b)
+ call void @doit(i64* inalloca(i64) %b)
ret void
}
define void @b() {
entry:
%a = alloca inalloca i64
- call void @doit(i64* inalloca %a)
- call void @doit(i64* inalloca %a)
+ call void @doit(i64* inalloca(i64) %a)
+ call void @doit(i64* inalloca(i64) %a)
ret void
}
call:
%args = phi i64* [ %a, %if ], [ %b, %else ]
- call void @doit(i64* inalloca %args)
+ call void @doit(i64* inalloca(i64) %args)
ret void
}
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
-declare void @doit(i64* inalloca %a)
+declare void @doit(i64* inalloca(i64) %a)
define void @a() {
entry:
%a = alloca [2 x i32]
%b = bitcast [2 x i32]* %a to i64*
- call void @doit(i64* inalloca %b)
+ call void @doit(i64* inalloca(i64) %b)
; CHECK: inalloca argument for call has mismatched alloca
ret void
}
; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s
-; CHECK: Wrong types for attribute: inalloca nest noalias nocapture noundef nonnull readnone readonly signext zeroext byref(void) byval(void) preallocated(void) sret(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
+; CHECK: Wrong types for attribute: nest noalias nocapture noundef nonnull readnone readonly signext zeroext byref(void) byval(void) inalloca(void) preallocated(void) sret(void) align 1 dereferenceable(1) dereferenceable_or_null(1)
; CHECK-NEXT: @noundef_void
define noundef void @noundef_void() {
ret void
Attribute A = Attribute::getWithByValType(C, Ty);
EXPECT_EQ(A.getAsString(), "byval(%mystruct)");
- A = Attribute::getWithByValType(C, nullptr);
- EXPECT_EQ(A.getAsString(), "byval");
-
A = Attribute::getWithByValType(C, Type::getInt32Ty(C));
EXPECT_EQ(A.getAsString(), "byval(i32)");
}
TEST(CloneFunction, CloneFunctionWithInalloca) {
StringRef ImplAssembly = R"(
- declare void @a(i32* inalloca)
+ declare void @a(i32* inalloca(i32))
define void @foo() {
%a = alloca inalloca i32
- call void @a(i32* inalloca %a)
+ call void @a(i32* inalloca(i32) %a)
ret void
}
declare void @bar()