Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[IR] Don't allow values of opaque type #137625

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 30, 2025
Merged

[IR] Don't allow values of opaque type #137625

merged 3 commits into from
Apr 30, 2025

Conversation

nikic
Copy link
Contributor

@nikic nikic commented Apr 28, 2025

Consider opaque types as non-first-class types, i.e. do not allow SSA values to have opaque type.

Consider opaque types as non-first-class types, i.e. do not allow
SSA values to have opaque type.
@llvmbot
Copy link
Member

llvmbot commented Apr 28, 2025

@llvm/pr-subscribers-backend-webassembly
@llvm/pr-subscribers-lto
@llvm/pr-subscribers-llvm-transforms
@llvm/pr-subscribers-backend-x86

@llvm/pr-subscribers-llvm-ir

Author: Nikita Popov (nikic)

Changes

Consider opaque types as non-first-class types, i.e. do not allow SSA values to have opaque type.


Full diff: https://github.com/llvm/llvm-project/pull/137625.diff

25 Files Affected:

  • (modified) llvm/include/llvm/IR/Type.h (+1-3)
  • (modified) llvm/lib/IR/Type.cpp (+14)
  • (modified) llvm/lib/Linker/IRMover.cpp (+2)
  • (modified) llvm/test/Assembler/2004-11-28-InvalidTypeCrash.ll (+1-1)
  • (modified) llvm/test/Assembler/2005-05-05-OpaqueUndefValues.ll (+3-2)
  • (modified) llvm/test/Assembler/2007-01-02-Undefined-Arg-Type.ll (+1-1)
  • (modified) llvm/test/CodeGen/WebAssembly/externref-unsized-load.ll (+1-1)
  • (modified) llvm/test/CodeGen/WebAssembly/externref-unsized-store.ll (+1-1)
  • (modified) llvm/test/CodeGen/X86/cfguard-x86-64-vectorcall.ll (+1-2)
  • (modified) llvm/test/CodeGen/X86/cfguard-x86-vectorcall.ll (+1-2)
  • (removed) llvm/test/Linker/Inputs/pr22807-1.ll (-6)
  • (renamed) llvm/test/Linker/Inputs/pr22807.ll (+1-3)
  • (modified) llvm/test/Linker/Inputs/type-unique-opaque.ll (+1-3)
  • (modified) llvm/test/Linker/intrinsics-with-unnamed-types.ll (+4-4)
  • (modified) llvm/test/Linker/pr22807.ll (+5-3)
  • (modified) llvm/test/Linker/type-unique-opaque.ll (+4-4)
  • (modified) llvm/test/ThinLTO/X86/Inputs/import_opaque_type.ll (+1-8)
  • (modified) llvm/test/ThinLTO/X86/import_opaque_type.ll (+5-10)
  • (modified) llvm/test/Transforms/InstSimplify/gv-alloca-cmp.ll (+1-1)
  • (modified) llvm/test/Transforms/Reg2Mem/non-token-test.ll (+6-8)
  • (modified) llvm/test/Verifier/memset-pattern-unsized.ll (+2-4)
  • (modified) llvm/test/Verifier/nofpclass.ll (-10)
  • (modified) llvm/test/Verifier/unsized-types-load.ll (+2-4)
  • (modified) llvm/test/Verifier/unsized-types-store.ll (+3-5)
  • (modified) llvm/unittests/FuzzMutate/OperationsTest.cpp (+2-3)
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<StructType>(this);
+      return !ST->isOpaque();
+    }
+  }
+}
+
 bool Type::isSizedDerivedType(SmallPtrSetImpl<Type*> *Visited) const {
   if (auto *ATy = dyn_cast<ArrayType>(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<GlobalVariable>(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"
                            "}";

Copy link

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff HEAD~1 HEAD --extensions cpp,h -- llvm/include/llvm/IR/Type.h llvm/lib/IR/Type.cpp llvm/lib/Linker/IRMover.cpp llvm/unittests/FuzzMutate/OperationsTest.cpp
View the diff from clang-format here.
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 3763980e9..a447baea3 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -249,15 +249,15 @@ int Type::getFPMantissaWidth() const {
 
 bool Type::isFirstClassType() const {
   switch (getTypeID()) {
-    default:
-      return true;
-    case FunctionTyID:
-    case VoidTyID:
-      return false;
-    case StructTyID: {
-      auto *ST = cast<StructType>(this);
-      return !ST->isOpaque();
-    }
+  default:
+    return true;
+  case FunctionTyID:
+  case VoidTyID:
+    return false;
+  case StructTyID: {
+    auto *ST = cast<StructType>(this);
+    return !ST->isOpaque();
+  }
   }
 }
 

Copy link

⚠️ undef deprecator found issues in your code. ⚠️

You can test this locally with the following command:
git diff -U0 --pickaxe-regex -S '([^a-zA-Z0-9#_-]undef[^a-zA-Z0-9_-]|UndefValue::get)' 'HEAD~1' HEAD llvm/include/llvm/IR/Type.h llvm/lib/IR/Type.cpp llvm/lib/Linker/IRMover.cpp llvm/test/Assembler/2004-11-28-InvalidTypeCrash.ll llvm/test/Assembler/2005-05-05-OpaqueUndefValues.ll llvm/test/Assembler/2007-01-02-Undefined-Arg-Type.ll llvm/test/CodeGen/WebAssembly/externref-unsized-load.ll llvm/test/CodeGen/WebAssembly/externref-unsized-store.ll llvm/test/CodeGen/X86/cfguard-x86-64-vectorcall.ll llvm/test/CodeGen/X86/cfguard-x86-vectorcall.ll llvm/test/Linker/Inputs/type-unique-opaque.ll llvm/test/Linker/intrinsics-with-unnamed-types.ll llvm/test/Linker/pr22807.ll llvm/test/Linker/type-unique-opaque.ll llvm/test/ThinLTO/X86/Inputs/import_opaque_type.ll llvm/test/ThinLTO/X86/import_opaque_type.ll llvm/test/Transforms/InstSimplify/gv-alloca-cmp.ll llvm/test/Transforms/Reg2Mem/non-token-test.ll llvm/test/Verifier/memset-pattern-unsized.ll llvm/test/Verifier/nofpclass.ll llvm/test/Verifier/unsized-types-load.ll llvm/test/Verifier/unsized-types-store.ll llvm/unittests/FuzzMutate/OperationsTest.cpp llvm/test/Linker/Inputs/pr22807.ll

The following files introduce new uses of undef:

  • llvm/test/Assembler/2005-05-05-OpaqueUndefValues.ll
  • llvm/test/CodeGen/WebAssembly/externref-unsized-store.ll

Undef is now deprecated and should only be used in the rare cases where no replacement is possible. For example, a load of uninitialized memory yields undef. You should use poison values for placeholders instead.

In tests, avoid using undef and having tests that trigger undefined behavior. If you need an operand with some unimportant value, you can add a new argument to the function and use that instead.

For example, this is considered a bad practice:

define void @fn() {
  ...
  br i1 undef, ...
}

Please use the following instead:

define void @fn(i1 %cond) {
  ...
  br i1 %cond, ...
}

Please refer to the Undefined Behavior Manual for more information.

@jayfoad
Copy link
Contributor

jayfoad commented Apr 28, 2025

This feels like it should need a change in LangRef.

@nikic
Copy link
Contributor Author

nikic commented Apr 28, 2025

This feels like it should need a change in LangRef.

Done.

@jayfoad
Copy link
Contributor

jayfoad commented Apr 28, 2025

This feels like it should need a change in LangRef.

Done.

Thanks. But if I'm reading the markup right, the LangRef still has the "Opaque Structure Types" section as a subsection of the "First Class Types" section. (But this is really non-obvious to the reader anyway, so perhaps we should switch to a different way of documenting the different "kinds" of types.)

@nikic
Copy link
Contributor Author

nikic commented Apr 28, 2025

This feels like it should need a change in LangRef.

Done.

Thanks. But if I'm reading the markup right, the LangRef still has the "Opaque Structure Types" section as a subsection of the "First Class Types" section. (But this is really non-obvious to the reader anyway, so perhaps we should switch to a different way of documenting the different "kinds" of types.)

Huh, I didn't even realize we had a separate section for first class types. I've now moved opaque types out of it, even if it's a bit weird to separate them from the other struct types.

Copy link
Member

@dtcxzyw dtcxzyw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LG

@nikic nikic merged commit 6feb4a8 into llvm:main Apr 30, 2025
11 of 12 checks passed
@nikic nikic deleted the no-opaque-values branch April 30, 2025 13:01
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
Consider opaque types as non-first-class types, i.e. do not allow SSA
values to have opaque type.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
Consider opaque types as non-first-class types, i.e. do not allow SSA
values to have opaque type.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
Consider opaque types as non-first-class types, i.e. do not allow SSA
values to have opaque type.
GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
Consider opaque types as non-first-class types, i.e. do not allow SSA
values to have opaque type.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants