Skip to content

Commit 6feb4a8

Browse files
authored
[IR] Don't allow values of opaque type (llvm#137625)
Consider opaque types as non-first-class types, i.e. do not allow SSA values to have opaque type.
1 parent f1248d6 commit 6feb4a8

26 files changed

+87
-114
lines changed

llvm/docs/LangRef.rst

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4122,6 +4122,30 @@ except :ref:`label <t_label>` and :ref:`metadata <t_metadata>`.
41224122
| ``{i32, i32} (i32)`` | A function taking an ``i32``, returning a :ref:`structure <t_struct>` containing two ``i32`` values |
41234123
+---------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+
41244124

4125+
.. _t_opaque:
4126+
4127+
Opaque Structure Types
4128+
----------------------
4129+
4130+
:Overview:
4131+
4132+
Opaque structure types are used to represent structure types that
4133+
do not have a body specified. This corresponds (for example) to the C
4134+
notion of a forward declared structure. They can be named (``%X``) or
4135+
unnamed (``%52``).
4136+
4137+
It is not possible to create SSA values with an opaque structure type. In
4138+
practice, this largely limits their use to the value type of external globals.
4139+
4140+
:Syntax:
4141+
4142+
::
4143+
4144+
%X = type opaque
4145+
%52 = type opaque
4146+
4147+
@g = external global %X
4148+
41254149
.. _t_firstclass:
41264150

41274151
First Class Types
@@ -4562,31 +4586,6 @@ opaqued and are never uniqued. Identified types must not be recursive.
45624586
| ``<{ i8, i32 }>`` | A packed struct known to be 5 bytes in size. |
45634587
+------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
45644588

4565-
.. _t_opaque:
4566-
4567-
Opaque Structure Types
4568-
""""""""""""""""""""""
4569-
4570-
:Overview:
4571-
4572-
Opaque structure types are used to represent structure types that
4573-
do not have a body specified. This corresponds (for example) to the C
4574-
notion of a forward declared structure. They can be named (``%X``) or
4575-
unnamed (``%52``).
4576-
4577-
:Syntax:
4578-
4579-
::
4580-
4581-
%X = type opaque
4582-
%52 = type opaque
4583-
4584-
:Examples:
4585-
4586-
+--------------+-------------------+
4587-
| ``opaque`` | An opaque type. |
4588-
+--------------+-------------------+
4589-
45904589
.. _constants:
45914590

45924591
Constants

llvm/include/llvm/IR/Type.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -286,9 +286,7 @@ class Type {
286286

287287
/// Return true if the type is "first class", meaning it is a valid type for a
288288
/// Value.
289-
bool isFirstClassType() const {
290-
return getTypeID() != FunctionTyID && getTypeID() != VoidTyID;
291-
}
289+
bool isFirstClassType() const;
292290

293291
/// Return true if the type is a valid type for a register in codegen. This
294292
/// includes all first-class types except struct and array types.

llvm/lib/IR/Type.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,20 @@ int Type::getFPMantissaWidth() const {
247247
return -1;
248248
}
249249

250+
bool Type::isFirstClassType() const {
251+
switch (getTypeID()) {
252+
default:
253+
return true;
254+
case FunctionTyID:
255+
case VoidTyID:
256+
return false;
257+
case StructTyID: {
258+
auto *ST = cast<StructType>(this);
259+
return !ST->isOpaque();
260+
}
261+
}
262+
}
263+
250264
bool Type::isSizedDerivedType(SmallPtrSetImpl<Type*> *Visited) const {
251265
if (auto *ATy = dyn_cast<ArrayType>(this))
252266
return ATy->getElementType()->isSized(Visited);

llvm/lib/Linker/IRMover.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,6 +1640,8 @@ Error IRLinker::run() {
16401640
if (GV.hasAppendingLinkage())
16411641
continue;
16421642
Value *NewValue = Mapper.mapValue(GV);
1643+
if (FoundError)
1644+
return std::move(*FoundError);
16431645
if (NewValue) {
16441646
auto *NewGV = dyn_cast<GlobalVariable>(NewValue->stripPointerCasts());
16451647
if (NewGV) {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; Test for PR463. This program is erroneous, but should not crash llvm-as.
22
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
3-
; CHECK: use of undefined type named 'struct.none'
3+
; CHECK: invalid type for null constant
44

55
@.FOO = internal global %struct.none zeroinitializer
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
; RUN: llvm-as < %s | llvm-dis | llvm-as > /dev/null
2-
; RUN: verify-uselistorder %s
1+
; RUN: not llvm-as < %s 2>&1 | FileCheck %s
2+
3+
; CHECK: error: invalid type for undef constant
34

45
%t = type opaque
56
@x = global %t undef

llvm/test/Assembler/2007-01-02-Undefined-Arg-Type.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
; The assembler should catch an undefined argument type .
22
; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
33

4-
; CHECK: use of undefined type named 'typedef.bc_struct'
4+
; CHECK: invalid type for function argument
55

66
; %typedef.bc_struct = type opaque
77

llvm/test/CodeGen/WebAssembly/externref-unsized-load.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ define void @load_extern(%externref %ref) {
77
ret void
88
}
99

10-
; CHECK-ERROR: error: loading unsized types is not allowed
10+
; CHECK-ERROR: error: load operand must be a pointer to a first class type

llvm/test/CodeGen/WebAssembly/externref-unsized-store.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ define void @store_extern(%externref %ref) {
77
ret void
88
}
99

10-
; CHECK-ERROR: error: storing unsized types is not allowed
10+
; CHECK-ERROR: error: invalid type for undef constant

llvm/test/CodeGen/X86/cfguard-x86-64-vectorcall.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
; RUN: llc < %s -mtriple=x86_64-w64-windows-gnu | FileCheck %s -check-prefix=X64
44
; Control Flow Guard is currently only available on Windows
55

6+
%struct.HVA = type { double, double, double, double }
67

78
; Test that Control Flow Guard checks are correctly added for x86_64 vector calls.
89
define void @func_cf_vector_x64(ptr %0, ptr %1) #0 {
@@ -37,8 +38,6 @@ entry:
3738
}
3839
attributes #0 = { "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" }
3940

40-
%struct.HVA = type { double, double, double, double }
41-
4241
declare void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1 immarg) #1
4342
attributes #1 = { argmemonly nounwind willreturn }
4443

llvm/test/CodeGen/X86/cfguard-x86-vectorcall.ll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
; RUN: llc < %s -mtriple=i686-w64-windows-gnu | FileCheck %s -check-prefix=X86
33
; Control Flow Guard is currently only available on Windows
44

5+
%struct.HVA = type { double, double, double, double }
56

67
; Test that Control Flow Guard checks are correctly added for x86 vector calls.
78
define void @func_cf_vector_x86(ptr %0, ptr %1) #0 {
@@ -32,8 +33,6 @@ entry:
3233
}
3334
attributes #0 = { "target-cpu"="pentium4" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" }
3435

35-
%struct.HVA = type { double, double, double, double }
36-
3736
declare void @llvm.memcpy.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #1
3837
attributes #1 = { argmemonly nounwind willreturn }
3938

llvm/test/Linker/Inputs/pr22807-1.ll

Lines changed: 0 additions & 6 deletions
This file was deleted.
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
%struct.A = type { %struct.B }
22
%struct.B = type opaque
33

4-
define i32 @bar(%struct.A %A) {
5-
ret i32 0
6-
}
4+
@g = external global %struct.A
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
%t = type { i8 }
22
%t2 = type { %t, i16 }
33

4-
define %t2 @f() {
5-
ret %t2 { %t { i8 0 }, i16 0 }
6-
}
4+
@g = external global %t2

llvm/test/Linker/intrinsics-with-unnamed-types.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
; Make sure we can link files with clashing intrinsic names using unnamed types.
88

99
;--- f01.ll
10-
%1 = type opaque
11-
%0 = type opaque
10+
%1 = type { i32 }
11+
%0 = type { i64 }
1212

1313
; CHECK-LABEL: @test01(
1414
; CHECK: %c1 = call %0 @llvm.ssa.copy.s_s.0(%0 %arg)
@@ -38,8 +38,8 @@ bb:
3838
}
3939

4040
;--- f02.ll
41-
%1 = type opaque
42-
%2 = type opaque
41+
%1 = type { i8 }
42+
%2 = type { i16 }
4343

4444
; CHECK-LABEL: @test03(
4545
; CHECK: %c1 = call %3 @llvm.ssa.copy.s_s.2(%3 %arg)

llvm/test/Linker/pr22807.ll

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
; RUN: not llvm-link -S -o - %p/pr22807.ll %p/Inputs/pr22807-1.ll %p/Inputs/pr22807-2.ll 2>&1 | FileCheck %s
1+
; RUN: not llvm-link -S -o - %p/pr22807.ll %p/Inputs/pr22807.ll 2>&1 | FileCheck %s
22

33
; CHECK: error: identified structure type 'struct.A' is recursive
44

55
%struct.B = type { %struct.A }
66
%struct.A = type opaque
77

8-
define i32 @baz(%struct.B %BB) {
9-
ret i32 0
8+
@g = external global %struct.B
9+
10+
define ptr @test() {
11+
ret ptr @g
1012
}

llvm/test/Linker/type-unique-opaque.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
; not cause %u and %t to get merged.
55

66
; CHECK: %u = type opaque
7-
; CHECK: define %u @g(%u %a) {
7+
; CHECK: external global %u
88

99
%u = type opaque
1010
%u2 = type { %u, i8 }
1111

12-
declare %u2 @f()
12+
@g = external global %u
1313

14-
define %u @g(%u %a) {
15-
ret %u %a
14+
define ptr @test() {
15+
ret ptr @g
1616
}

llvm/test/ThinLTO/X86/Inputs/import_opaque_type.ll

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,4 @@ target triple = "x86_64-apple-macosx10.11.0"
33

44
%a = type { i8 }
55

6-
define void @bar(%a) {
7-
ret void
8-
}
9-
10-
define void @baz() {
11-
call void @bar(%a undef)
12-
ret void
13-
}
6+
@g = external global %a

llvm/test/ThinLTO/X86/import_opaque_type.ll

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,18 @@
33
; RUN: opt -module-summary %p/Inputs/import_opaque_type.ll -o %t2.bc
44
; RUN: llvm-lto -thinlto-action=thinlink -o %t3.bc %t.bc %t2.bc
55

6-
; Check that we import correctly the imported type to replace the opaque one here
76
; RUN: llvm-lto -thinlto-action=import %t.bc -thinlto-index=%t3.bc -o - | llvm-dis -o - | FileCheck %s
87

98

109
target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
1110
target triple = "x86_64-apple-macosx10.11.0"
1211

13-
; CHECK: %a = type { i8 }
12+
; FIXME: It would be better to produce %a = type { i8 } here
13+
; CHECK: %a = type opaque
1414
%a = type opaque
1515

16-
declare void @baz()
17-
define void @foo(%a) {
18-
call void @baz()
19-
ret void
20-
}
16+
@g = external global %a
2117

22-
define i32 @main() {
23-
call void @foo(%a undef)
24-
ret i32 0
18+
define ptr @test() {
19+
ret ptr @g
2520
}

llvm/test/Transforms/InstSimplify/gv-alloca-cmp.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ define i1 @cmp_gv_weak_alloca() {
4646
}
4747

4848
%opaque = type opaque
49-
@gv_unsized = weak global %opaque zeroinitializer, align 16
49+
@gv_unsized = external global %opaque, align 16
5050

5151
define i1 @cmp_gv_unsized_alloca() {
5252
; CHECK-LABEL: define i1 @cmp_gv_unsized_alloca() {
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
22
; RUN: opt -passes=reg2mem -S < %s | FileCheck %s
33

4-
%opaque = type opaque
5-
6-
declare %opaque @ret_opaque()
7-
declare void @pass_opaque(%opaque)
4+
declare target("opaque") @ret_opaque()
5+
declare void @pass_opaque(target("opaque"))
86

97
define void @test() {
108
; CHECK-LABEL: @test(
119
; CHECK-NEXT: %"reg2mem alloca point" = bitcast i32 0 to i32
12-
; CHECK-NEXT: [[X:%.*]] = call [[OPAQUE:%.*]] @ret_opaque()
10+
; CHECK-NEXT: [[X:%.*]] = call target("opaque") @ret_opaque()
1311
; CHECK-NEXT: br label [[NEXT:%.*]]
1412
; CHECK: next:
15-
; CHECK-NEXT: call void @pass_opaque([[OPAQUE]] [[X]])
13+
; CHECK-NEXT: call void @pass_opaque(target("opaque") [[X]])
1614
; CHECK-NEXT: ret void
1715
;
18-
%x = call %opaque @ret_opaque()
16+
%x = call target("opaque") @ret_opaque()
1917
br label %next
2018

2119
next:
22-
call void @pass_opaque(%opaque %x)
20+
call void @pass_opaque(target("opaque") %x)
2321
ret void
2422
}

llvm/test/Verifier/memset-pattern-unsized.ll

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
; CHECK: unsized types cannot be used as memset patterns
44

5-
%X = type opaque
6-
define void @bar(ptr %P, %X %value) {
7-
call void @llvm.experimental.memset.pattern.p0.s_s.i32.0(ptr %P, %X %value, i32 4, i1 false)
5+
define void @bar(ptr %P, target("foo") %value) {
6+
call void @llvm.experimental.memset.pattern.p0.s_s.i32.0(ptr %P, target("foo") %value, i32 4, i1 false)
87
ret void
98
}
10-
declare void @llvm.experimental.memset.pattern.p0.s_s.i32.0(ptr nocapture, %X, i32, i1) nounwind

llvm/test/Verifier/nofpclass.ll

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,6 @@ define nofpclass(nan) [4 x <8 x i32>] @nofpclass_vector_array_int([4 x <8 x i32>
4545
ret [4 x <8 x i32>] %arg
4646
}
4747

48-
%opaque = type opaque
49-
50-
; CHECK: 'nofpclass(nan)' applied to incompatible type!
51-
; CHECK-NEXT: ptr @nofpclass_opaque_type
52-
; CHECK-NEXT: 'nofpclass(zero)' applied to incompatible type!
53-
; CHECK-NEXT: ptr @nofpclass_opaque_type
54-
define nofpclass(nan) %opaque @nofpclass_opaque_type(%opaque nofpclass(zero) %arg) {
55-
ret %opaque %arg
56-
}
57-
5848
%struct = type { i32, float }
5949

6050
; CHECK: 'nofpclass(nan)' applied to incompatible type!
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
; RUN: not opt -passes=verify < %s 2>&1 | FileCheck %s
22

3-
%X = type opaque
4-
53
define void @f_0(ptr %ptr) {
6-
%t = load %X, ptr %ptr
4+
%t = load target("foo"), ptr %ptr
75
ret void
86
; CHECK: loading unsized types is not allowed
9-
; CHECK-NEXT: %t = load %X, ptr %ptr
7+
; CHECK-NEXT: %t = load target("foo"), ptr %ptr
108
}
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
; RUN: not opt -passes=verify < %s 2>&1 | FileCheck %s
22

3-
%X = type opaque
4-
5-
define void @f_1(%X %val, ptr %ptr) {
6-
store %X %val, ptr %ptr
3+
define void @f_1(target("foo") %val, ptr %ptr) {
4+
store target("foo") %val, ptr %ptr
75
ret void
86
; CHECK: storing unsized types is not allowed
9-
; CHECK-NEXT: store %X %val, ptr %ptr
7+
; CHECK-NEXT: store target("foo") %val, ptr %ptr
108
}

0 commit comments

Comments
 (0)