diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 5bd1d29487139..4aa81ad971729 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -4122,6 +4122,30 @@ except :ref:`label ` and :ref:`metadata `. | ``{i32, i32} (i32)`` | A function taking an ``i32``, returning a :ref:`structure ` containing two ``i32`` values | +---------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. _t_opaque: + +Opaque Structure Types +---------------------- + +:Overview: + +Opaque structure types are used to represent structure types that +do not have a body specified. This corresponds (for example) to the C +notion of a forward declared structure. They can be named (``%X``) or +unnamed (``%52``). + +It is not possible to create SSA values with an opaque structure type. In +practice, this largely limits their use to the value type of external globals. + +:Syntax: + +:: + + %X = type opaque + %52 = type opaque + + @g = external global %X + .. _t_firstclass: First Class Types @@ -4562,31 +4586,6 @@ opaqued and are never uniqued. Identified types must not be recursive. | ``<{ i8, i32 }>`` | A packed struct known to be 5 bytes in size. | +------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -.. _t_opaque: - -Opaque Structure Types -"""""""""""""""""""""" - -:Overview: - -Opaque structure types are used to represent structure types that -do not have a body specified. This corresponds (for example) to the C -notion of a forward declared structure. They can be named (``%X``) or -unnamed (``%52``). - -:Syntax: - -:: - - %X = type opaque - %52 = type opaque - -:Examples: - -+--------------+-------------------+ -| ``opaque`` | An opaque type. | -+--------------+-------------------+ - .. _constants: Constants diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h index a4c0648a9197e..37f6b2ed8ee68 100644 --- a/llvm/include/llvm/IR/Type.h +++ b/llvm/include/llvm/IR/Type.h @@ -286,9 +286,7 @@ class Type { /// Return true if the type is "first class", meaning it is a valid type for a /// Value. - bool isFirstClassType() const { - return getTypeID() != FunctionTyID && getTypeID() != VoidTyID; - } + bool isFirstClassType() const; /// Return true if the type is a valid type for a register in codegen. This /// includes all first-class types except struct and array types. diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp index 884609e734298..3763980e9db82 100644 --- a/llvm/lib/IR/Type.cpp +++ b/llvm/lib/IR/Type.cpp @@ -247,6 +247,20 @@ int Type::getFPMantissaWidth() const { return -1; } +bool Type::isFirstClassType() const { + switch (getTypeID()) { + default: + return true; + case FunctionTyID: + case VoidTyID: + return false; + case StructTyID: { + auto *ST = cast(this); + return !ST->isOpaque(); + } + } +} + bool Type::isSizedDerivedType(SmallPtrSetImpl *Visited) const { if (auto *ATy = dyn_cast(this)) return ATy->getElementType()->isSized(Visited); diff --git a/llvm/lib/Linker/IRMover.cpp b/llvm/lib/Linker/IRMover.cpp index 98d69051c935a..086718a188845 100644 --- a/llvm/lib/Linker/IRMover.cpp +++ b/llvm/lib/Linker/IRMover.cpp @@ -1640,6 +1640,8 @@ Error IRLinker::run() { if (GV.hasAppendingLinkage()) continue; Value *NewValue = Mapper.mapValue(GV); + if (FoundError) + return std::move(*FoundError); if (NewValue) { auto *NewGV = dyn_cast(NewValue->stripPointerCasts()); if (NewGV) { diff --git a/llvm/test/Assembler/2004-11-28-InvalidTypeCrash.ll b/llvm/test/Assembler/2004-11-28-InvalidTypeCrash.ll index 7260f19bfd9a5..98ad9eefdcd1e 100644 --- a/llvm/test/Assembler/2004-11-28-InvalidTypeCrash.ll +++ b/llvm/test/Assembler/2004-11-28-InvalidTypeCrash.ll @@ -1,5 +1,5 @@ ; Test for PR463. This program is erroneous, but should not crash llvm-as. ; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s -; CHECK: use of undefined type named 'struct.none' +; CHECK: invalid type for null constant @.FOO = internal global %struct.none zeroinitializer diff --git a/llvm/test/Assembler/2005-05-05-OpaqueUndefValues.ll b/llvm/test/Assembler/2005-05-05-OpaqueUndefValues.ll index 01456f10c9dc1..b14f4c16ab2d0 100644 --- a/llvm/test/Assembler/2005-05-05-OpaqueUndefValues.ll +++ b/llvm/test/Assembler/2005-05-05-OpaqueUndefValues.ll @@ -1,5 +1,6 @@ -; RUN: llvm-as < %s | llvm-dis | llvm-as > /dev/null -; RUN: verify-uselistorder %s +; RUN: not llvm-as < %s 2>&1 | FileCheck %s + +; CHECK: error: invalid type for undef constant %t = type opaque @x = global %t undef diff --git a/llvm/test/Assembler/2007-01-02-Undefined-Arg-Type.ll b/llvm/test/Assembler/2007-01-02-Undefined-Arg-Type.ll index 5f4db4ee06ba4..1d40c76bbad20 100644 --- a/llvm/test/Assembler/2007-01-02-Undefined-Arg-Type.ll +++ b/llvm/test/Assembler/2007-01-02-Undefined-Arg-Type.ll @@ -1,7 +1,7 @@ ; The assembler should catch an undefined argument type . ; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s -; CHECK: use of undefined type named 'typedef.bc_struct' +; CHECK: invalid type for function argument ; %typedef.bc_struct = type opaque diff --git a/llvm/test/CodeGen/WebAssembly/externref-unsized-load.ll b/llvm/test/CodeGen/WebAssembly/externref-unsized-load.ll index 945045d902ef5..1f8f4d5140c51 100644 --- a/llvm/test/CodeGen/WebAssembly/externref-unsized-load.ll +++ b/llvm/test/CodeGen/WebAssembly/externref-unsized-load.ll @@ -7,4 +7,4 @@ define void @load_extern(%externref %ref) { ret void } -; CHECK-ERROR: error: loading unsized types is not allowed +; CHECK-ERROR: error: load operand must be a pointer to a first class type diff --git a/llvm/test/CodeGen/WebAssembly/externref-unsized-store.ll b/llvm/test/CodeGen/WebAssembly/externref-unsized-store.ll index ca01f69a08ad2..c7e062d1b0526 100644 --- a/llvm/test/CodeGen/WebAssembly/externref-unsized-store.ll +++ b/llvm/test/CodeGen/WebAssembly/externref-unsized-store.ll @@ -7,4 +7,4 @@ define void @store_extern(%externref %ref) { ret void } -; CHECK-ERROR: error: storing unsized types is not allowed +; CHECK-ERROR: error: invalid type for undef constant diff --git a/llvm/test/CodeGen/X86/cfguard-x86-64-vectorcall.ll b/llvm/test/CodeGen/X86/cfguard-x86-64-vectorcall.ll index 8dc33fb98bf0c..7748f8007c619 100644 --- a/llvm/test/CodeGen/X86/cfguard-x86-64-vectorcall.ll +++ b/llvm/test/CodeGen/X86/cfguard-x86-64-vectorcall.ll @@ -3,6 +3,7 @@ ; RUN: llc < %s -mtriple=x86_64-w64-windows-gnu | FileCheck %s -check-prefix=X64 ; Control Flow Guard is currently only available on Windows +%struct.HVA = type { double, double, double, double } ; Test that Control Flow Guard checks are correctly added for x86_64 vector calls. define void @func_cf_vector_x64(ptr %0, ptr %1) #0 { @@ -37,8 +38,6 @@ entry: } attributes #0 = { "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" } -%struct.HVA = type { double, double, double, double } - declare void @llvm.memcpy.p0.p0.i64(ptr nocapture writeonly, ptr nocapture readonly, i64, i1 immarg) #1 attributes #1 = { argmemonly nounwind willreturn } diff --git a/llvm/test/CodeGen/X86/cfguard-x86-vectorcall.ll b/llvm/test/CodeGen/X86/cfguard-x86-vectorcall.ll index a75973310d15c..fd95e923df7ce 100644 --- a/llvm/test/CodeGen/X86/cfguard-x86-vectorcall.ll +++ b/llvm/test/CodeGen/X86/cfguard-x86-vectorcall.ll @@ -2,6 +2,7 @@ ; RUN: llc < %s -mtriple=i686-w64-windows-gnu | FileCheck %s -check-prefix=X86 ; Control Flow Guard is currently only available on Windows +%struct.HVA = type { double, double, double, double } ; Test that Control Flow Guard checks are correctly added for x86 vector calls. define void @func_cf_vector_x86(ptr %0, ptr %1) #0 { @@ -32,8 +33,6 @@ entry: } attributes #0 = { "target-cpu"="pentium4" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" } -%struct.HVA = type { double, double, double, double } - declare void @llvm.memcpy.p0.p0.i32(ptr nocapture writeonly, ptr nocapture readonly, i32, i1 immarg) #1 attributes #1 = { argmemonly nounwind willreturn } diff --git a/llvm/test/Linker/Inputs/pr22807-1.ll b/llvm/test/Linker/Inputs/pr22807-1.ll deleted file mode 100644 index a1006bf409a13..0000000000000 --- a/llvm/test/Linker/Inputs/pr22807-1.ll +++ /dev/null @@ -1,6 +0,0 @@ -%struct.A = type { %struct.B } -%struct.B = type opaque - -define i32 @foo(%struct.A** %A) { - ret i32 0 -} diff --git a/llvm/test/Linker/Inputs/pr22807-2.ll b/llvm/test/Linker/Inputs/pr22807.ll similarity index 54% rename from llvm/test/Linker/Inputs/pr22807-2.ll rename to llvm/test/Linker/Inputs/pr22807.ll index 137638e2987a2..d5ebcccb4756f 100644 --- a/llvm/test/Linker/Inputs/pr22807-2.ll +++ b/llvm/test/Linker/Inputs/pr22807.ll @@ -1,6 +1,4 @@ %struct.A = type { %struct.B } %struct.B = type opaque -define i32 @bar(%struct.A %A) { - ret i32 0 -} +@g = external global %struct.A diff --git a/llvm/test/Linker/Inputs/type-unique-opaque.ll b/llvm/test/Linker/Inputs/type-unique-opaque.ll index 2e6f45ec84fe1..9d12d3b19f3a7 100644 --- a/llvm/test/Linker/Inputs/type-unique-opaque.ll +++ b/llvm/test/Linker/Inputs/type-unique-opaque.ll @@ -1,6 +1,4 @@ %t = type { i8 } %t2 = type { %t, i16 } -define %t2 @f() { - ret %t2 { %t { i8 0 }, i16 0 } -} +@g = external global %t2 diff --git a/llvm/test/Linker/intrinsics-with-unnamed-types.ll b/llvm/test/Linker/intrinsics-with-unnamed-types.ll index 0772a764e10fa..d870e7f100e05 100644 --- a/llvm/test/Linker/intrinsics-with-unnamed-types.ll +++ b/llvm/test/Linker/intrinsics-with-unnamed-types.ll @@ -7,8 +7,8 @@ ; Make sure we can link files with clashing intrinsic names using unnamed types. ;--- f01.ll -%1 = type opaque -%0 = type opaque +%1 = type { i32 } +%0 = type { i64 } ; CHECK-LABEL: @test01( ; CHECK: %c1 = call %0 @llvm.ssa.copy.s_s.0(%0 %arg) @@ -38,8 +38,8 @@ bb: } ;--- f02.ll -%1 = type opaque -%2 = type opaque +%1 = type { i8 } +%2 = type { i16 } ; CHECK-LABEL: @test03( ; CHECK: %c1 = call %3 @llvm.ssa.copy.s_s.2(%3 %arg) diff --git a/llvm/test/Linker/pr22807.ll b/llvm/test/Linker/pr22807.ll index a1fe38480c6ee..24bcf1732112b 100644 --- a/llvm/test/Linker/pr22807.ll +++ b/llvm/test/Linker/pr22807.ll @@ -1,10 +1,12 @@ -; RUN: not llvm-link -S -o - %p/pr22807.ll %p/Inputs/pr22807-1.ll %p/Inputs/pr22807-2.ll 2>&1 | FileCheck %s +; RUN: not llvm-link -S -o - %p/pr22807.ll %p/Inputs/pr22807.ll 2>&1 | FileCheck %s ; CHECK: error: identified structure type 'struct.A' is recursive %struct.B = type { %struct.A } %struct.A = type opaque -define i32 @baz(%struct.B %BB) { - ret i32 0 +@g = external global %struct.B + +define ptr @test() { + ret ptr @g } diff --git a/llvm/test/Linker/type-unique-opaque.ll b/llvm/test/Linker/type-unique-opaque.ll index 72466f2e134a2..3fc49b50102f0 100644 --- a/llvm/test/Linker/type-unique-opaque.ll +++ b/llvm/test/Linker/type-unique-opaque.ll @@ -4,13 +4,13 @@ ; not cause %u and %t to get merged. ; CHECK: %u = type opaque -; CHECK: define %u @g(%u %a) { +; CHECK: external global %u %u = type opaque %u2 = type { %u, i8 } -declare %u2 @f() +@g = external global %u -define %u @g(%u %a) { - ret %u %a +define ptr @test() { + ret ptr @g } diff --git a/llvm/test/ThinLTO/X86/Inputs/import_opaque_type.ll b/llvm/test/ThinLTO/X86/Inputs/import_opaque_type.ll index ecdaa727fb0df..e72f2d9fe57f6 100644 --- a/llvm/test/ThinLTO/X86/Inputs/import_opaque_type.ll +++ b/llvm/test/ThinLTO/X86/Inputs/import_opaque_type.ll @@ -3,11 +3,4 @@ target triple = "x86_64-apple-macosx10.11.0" %a = type { i8 } -define void @bar(%a) { - ret void -} - -define void @baz() { - call void @bar(%a undef) - ret void -} +@g = external global %a diff --git a/llvm/test/ThinLTO/X86/import_opaque_type.ll b/llvm/test/ThinLTO/X86/import_opaque_type.ll index ecb7b927bd8b6..1e8aade3eccd3 100644 --- a/llvm/test/ThinLTO/X86/import_opaque_type.ll +++ b/llvm/test/ThinLTO/X86/import_opaque_type.ll @@ -3,23 +3,18 @@ ; RUN: opt -module-summary %p/Inputs/import_opaque_type.ll -o %t2.bc ; RUN: llvm-lto -thinlto-action=thinlink -o %t3.bc %t.bc %t2.bc -; Check that we import correctly the imported type to replace the opaque one here ; RUN: llvm-lto -thinlto-action=import %t.bc -thinlto-index=%t3.bc -o - | llvm-dis -o - | FileCheck %s target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.11.0" -; CHECK: %a = type { i8 } +; FIXME: It would be better to produce %a = type { i8 } here +; CHECK: %a = type opaque %a = type opaque -declare void @baz() -define void @foo(%a) { - call void @baz() - ret void -} +@g = external global %a -define i32 @main() { - call void @foo(%a undef) - ret i32 0 +define ptr @test() { + ret ptr @g } diff --git a/llvm/test/Transforms/InstSimplify/gv-alloca-cmp.ll b/llvm/test/Transforms/InstSimplify/gv-alloca-cmp.ll index 4f2544052b215..f30c6379e47e1 100644 --- a/llvm/test/Transforms/InstSimplify/gv-alloca-cmp.ll +++ b/llvm/test/Transforms/InstSimplify/gv-alloca-cmp.ll @@ -46,7 +46,7 @@ define i1 @cmp_gv_weak_alloca() { } %opaque = type opaque -@gv_unsized = weak global %opaque zeroinitializer, align 16 +@gv_unsized = external global %opaque, align 16 define i1 @cmp_gv_unsized_alloca() { ; CHECK-LABEL: define i1 @cmp_gv_unsized_alloca() { diff --git a/llvm/test/Transforms/Reg2Mem/non-token-test.ll b/llvm/test/Transforms/Reg2Mem/non-token-test.ll index e30f37abaa443..cdf09bb6de9b4 100644 --- a/llvm/test/Transforms/Reg2Mem/non-token-test.ll +++ b/llvm/test/Transforms/Reg2Mem/non-token-test.ll @@ -1,24 +1,22 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -passes=reg2mem -S < %s | FileCheck %s -%opaque = type opaque - -declare %opaque @ret_opaque() -declare void @pass_opaque(%opaque) +declare target("opaque") @ret_opaque() +declare void @pass_opaque(target("opaque")) define void @test() { ; CHECK-LABEL: @test( ; CHECK-NEXT: %"reg2mem alloca point" = bitcast i32 0 to i32 -; CHECK-NEXT: [[X:%.*]] = call [[OPAQUE:%.*]] @ret_opaque() +; CHECK-NEXT: [[X:%.*]] = call target("opaque") @ret_opaque() ; CHECK-NEXT: br label [[NEXT:%.*]] ; CHECK: next: -; CHECK-NEXT: call void @pass_opaque([[OPAQUE]] [[X]]) +; CHECK-NEXT: call void @pass_opaque(target("opaque") [[X]]) ; CHECK-NEXT: ret void ; - %x = call %opaque @ret_opaque() + %x = call target("opaque") @ret_opaque() br label %next next: - call void @pass_opaque(%opaque %x) + call void @pass_opaque(target("opaque") %x) ret void } diff --git a/llvm/test/Verifier/memset-pattern-unsized.ll b/llvm/test/Verifier/memset-pattern-unsized.ll index 71b7dca9a5a19..784fe1c7484ee 100644 --- a/llvm/test/Verifier/memset-pattern-unsized.ll +++ b/llvm/test/Verifier/memset-pattern-unsized.ll @@ -2,9 +2,7 @@ ; CHECK: unsized types cannot be used as memset patterns -%X = type opaque -define void @bar(ptr %P, %X %value) { - call void @llvm.experimental.memset.pattern.p0.s_s.i32.0(ptr %P, %X %value, i32 4, i1 false) +define void @bar(ptr %P, target("foo") %value) { + call void @llvm.experimental.memset.pattern.p0.s_s.i32.0(ptr %P, target("foo") %value, i32 4, i1 false) ret void } -declare void @llvm.experimental.memset.pattern.p0.s_s.i32.0(ptr nocapture, %X, i32, i1) nounwind diff --git a/llvm/test/Verifier/nofpclass.ll b/llvm/test/Verifier/nofpclass.ll index ea140ac6d97ef..3569598e91fb8 100644 --- a/llvm/test/Verifier/nofpclass.ll +++ b/llvm/test/Verifier/nofpclass.ll @@ -45,16 +45,6 @@ define nofpclass(nan) [4 x <8 x i32>] @nofpclass_vector_array_int([4 x <8 x i32> ret [4 x <8 x i32>] %arg } -%opaque = type opaque - -; CHECK: 'nofpclass(nan)' applied to incompatible type! -; CHECK-NEXT: ptr @nofpclass_opaque_type -; CHECK-NEXT: 'nofpclass(zero)' applied to incompatible type! -; CHECK-NEXT: ptr @nofpclass_opaque_type -define nofpclass(nan) %opaque @nofpclass_opaque_type(%opaque nofpclass(zero) %arg) { - ret %opaque %arg -} - %struct = type { i32, float } ; CHECK: 'nofpclass(nan)' applied to incompatible type! diff --git a/llvm/test/Verifier/unsized-types-load.ll b/llvm/test/Verifier/unsized-types-load.ll index fed6540f2c8cb..5959ddc8fde0e 100644 --- a/llvm/test/Verifier/unsized-types-load.ll +++ b/llvm/test/Verifier/unsized-types-load.ll @@ -1,10 +1,8 @@ ; RUN: not opt -passes=verify < %s 2>&1 | FileCheck %s -%X = type opaque - define void @f_0(ptr %ptr) { - %t = load %X, ptr %ptr + %t = load target("foo"), ptr %ptr ret void ; CHECK: loading unsized types is not allowed -; CHECK-NEXT: %t = load %X, ptr %ptr +; CHECK-NEXT: %t = load target("foo"), ptr %ptr } diff --git a/llvm/test/Verifier/unsized-types-store.ll b/llvm/test/Verifier/unsized-types-store.ll index 3748fde8470ef..7b7e0e8c8a6ed 100644 --- a/llvm/test/Verifier/unsized-types-store.ll +++ b/llvm/test/Verifier/unsized-types-store.ll @@ -1,10 +1,8 @@ ; RUN: not opt -passes=verify < %s 2>&1 | FileCheck %s -%X = type opaque - -define void @f_1(%X %val, ptr %ptr) { - store %X %val, ptr %ptr +define void @f_1(target("foo") %val, ptr %ptr) { + store target("foo") %val, ptr %ptr ret void ; CHECK: storing unsized types is not allowed -; CHECK-NEXT: store %X %val, ptr %ptr +; CHECK-NEXT: store target("foo") %val, ptr %ptr } diff --git a/llvm/unittests/FuzzMutate/OperationsTest.cpp b/llvm/unittests/FuzzMutate/OperationsTest.cpp index e4ee6d96ba187..666931c9f40f4 100644 --- a/llvm/unittests/FuzzMutate/OperationsTest.cpp +++ b/llvm/unittests/FuzzMutate/OperationsTest.cpp @@ -380,9 +380,8 @@ TEST(OperationsTest, GEPPointerOperand) { // Check that we only pick sized pointers for the GEP instructions LLVMContext Ctx; - const char *SourceCode = "%opaque = type opaque\n" - "declare void @f()\n" - "define void @test(%opaque %o) {\n" + const char *SourceCode = "declare void @f()\n" + "define void @test(target(\"foo\") %o) {\n" " %a = alloca i64, i32 10\n" " ret void\n" "}";