[llvm] [llvm][rtsan] Add transform pass for sanitize_realtime_unsafe (PR #109543)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 24 10:08:58 PDT 2024
https://github.com/davidtrevelyan updated https://github.com/llvm/llvm-project/pull/109543
>From 5c3e345d1a02ca1ebbc4243f23f7f1fb5d37ec6a Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Fri, 30 Aug 2024 15:14:24 +0100
Subject: [PATCH 1/7] Implement sanitize_realtime_unsafe Pass
---
.../Instrumentation/RealtimeSanitizer.cpp | 28 +++++++++++++++++--
.../RealtimeSanitizer/rtsan_unsafe.ll | 16 +++++++++++
2 files changed, 41 insertions(+), 3 deletions(-)
create mode 100644 llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index 7854cf4f2c625f..ae60122c13b079 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -45,6 +45,26 @@ static void insertCallAtAllFunctionExitPoints(Function &Fn,
insertCallBeforeInstruction(Fn, I, InsertFnName);
}
+static PreservedAnalyses rtsanPreservedAnalyses() {
+ PreservedAnalyses PA;
+ PA.preserveSet<CFGAnalyses>();
+ return PA;
+}
+
+static void transformRealtimeUnsafeFunction(Function &F) {
+ IRBuilder<> Builder(&F.front().front());
+ Value *NameArg = Builder.CreateGlobalString(F.getName());
+
+ FunctionType *FuncType =
+ FunctionType::get(Type::getVoidTy(F.getContext()),
+ {PointerType::getUnqual(F.getContext())}, false);
+
+ FunctionCallee Func = F.getParent()->getOrInsertFunction(
+ "__rtsan_expect_not_realtime", FuncType);
+
+ Builder.CreateCall(Func, {NameArg});
+}
+
RealtimeSanitizerPass::RealtimeSanitizerPass(
const RealtimeSanitizerOptions &Options) {}
@@ -53,10 +73,12 @@ PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
if (F.hasFnAttribute(Attribute::SanitizeRealtime)) {
insertCallAtFunctionEntryPoint(F, "__rtsan_realtime_enter");
insertCallAtAllFunctionExitPoints(F, "__rtsan_realtime_exit");
+ return rtsanPreservedAnalyses();
+ }
- PreservedAnalyses PA;
- PA.preserveSet<CFGAnalyses>();
- return PA;
+ if (F.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
+ transformRealtimeUnsafeFunction(F);
+ return rtsanPreservedAnalyses();
}
return PreservedAnalyses::all();
diff --git a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
new file mode 100644
index 00000000000000..646a9a0e22e213
--- /dev/null
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
@@ -0,0 +1,16 @@
+; RUN: opt < %s -passes=rtsan -S | FileCheck %s
+
+define void @blocking_function() #0 {
+ ret void
+}
+
+define noundef i32 @main() #2 {
+ call void @blocking_function() #4
+ ret i32 0
+}
+
+attributes #0 = { mustprogress noinline sanitize_realtime_unsafe optnone ssp uwtable(sync) }
+
+; RealtimeSanitizer pass should insert __rtsan_expect_not_realtime at function entrypoint
+; CHECK-LABEL: @blocking_function()
+; CHECK-NEXT: call{{.*}}@__rtsan_expect_not_realtime({{ptr .*}})
>From 21b7f16c4d302a9e4363263d101f72e8535e8f72 Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Fri, 30 Aug 2024 16:24:06 +0100
Subject: [PATCH 2/7] Rename rtsan pass functions to be more explicit
---
.../Transforms/Instrumentation/RealtimeSanitizer.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index ae60122c13b079..b977badc9d6c1f 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -45,13 +45,13 @@ static void insertCallAtAllFunctionExitPoints(Function &Fn,
insertCallBeforeInstruction(Fn, I, InsertFnName);
}
-static PreservedAnalyses rtsanPreservedAnalyses() {
+static PreservedAnalyses rtsanPreservedCFGAnalyses() {
PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
return PA;
}
-static void transformRealtimeUnsafeFunction(Function &F) {
+static void insertExpectNotRealtimeAtFunctionEntryPoint(Function &F) {
IRBuilder<> Builder(&F.front().front());
Value *NameArg = Builder.CreateGlobalString(F.getName());
@@ -73,12 +73,12 @@ PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
if (F.hasFnAttribute(Attribute::SanitizeRealtime)) {
insertCallAtFunctionEntryPoint(F, "__rtsan_realtime_enter");
insertCallAtAllFunctionExitPoints(F, "__rtsan_realtime_exit");
- return rtsanPreservedAnalyses();
+ return rtsanPreservedCFGAnalyses();
}
if (F.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
- transformRealtimeUnsafeFunction(F);
- return rtsanPreservedAnalyses();
+ insertExpectNotRealtimeAtFunctionEntryPoint(F);
+ return rtsanPreservedCFGAnalyses();
}
return PreservedAnalyses::all();
>From b0e4cf35c36f1738d6ddb665187bd02f6bd9e97f Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Sat, 31 Aug 2024 19:04:23 +0100
Subject: [PATCH 3/7] Demangle [[clang::blocking]] function names in rtsan pass
---
.../Instrumentation/RealtimeSanitizer.cpp | 3 ++-
.../RealtimeSanitizer/rtsan_unsafe.ll | 13 ++++++++-----
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index b977badc9d6c1f..c3ea1471796bdf 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -17,6 +17,7 @@
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
+#include "llvm/Demangle/Demangle.h"
#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
using namespace llvm;
@@ -53,7 +54,7 @@ static PreservedAnalyses rtsanPreservedCFGAnalyses() {
static void insertExpectNotRealtimeAtFunctionEntryPoint(Function &F) {
IRBuilder<> Builder(&F.front().front());
- Value *NameArg = Builder.CreateGlobalString(F.getName());
+ Value *NameArg = Builder.CreateGlobalString(demangle(F.getName()));
FunctionType *FuncType =
FunctionType::get(Type::getVoidTy(F.getContext()),
diff --git a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
index 646a9a0e22e213..0df01b95a79aea 100644
--- a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
@@ -1,16 +1,19 @@
; RUN: opt < %s -passes=rtsan -S | FileCheck %s
-define void @blocking_function() #0 {
+define void @_Z17blocking_functionv() #0 {
ret void
}
define noundef i32 @main() #2 {
- call void @blocking_function() #4
+ call void @_Z17blocking_functionv() #4
ret i32 0
}
attributes #0 = { mustprogress noinline sanitize_realtime_unsafe optnone ssp uwtable(sync) }
-; RealtimeSanitizer pass should insert __rtsan_expect_not_realtime at function entrypoint
-; CHECK-LABEL: @blocking_function()
-; CHECK-NEXT: call{{.*}}@__rtsan_expect_not_realtime({{ptr .*}})
+; RealtimeSanitizer pass should create the demangled function name as a global string, and
+; pass it as input to an inserted __rtsan_expect_not_realtime call at the function entrypoint
+; CHECK: [[GLOBAL_STR:@[a-zA-Z0-9\.]+]]
+; CHECK-SAME: c"blocking_function()\00"
+; CHECK-LABEL: @_Z17blocking_functionv()
+; CHECK-NEXT: call{{.*}}@__rtsan_expect_not_realtime(ptr{{.*}}[[GLOBAL_STR]])
>From c3dd787b960e48799decfbfbebdf22534b51d7a3 Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Sat, 21 Sep 2024 12:47:43 -0600
Subject: [PATCH 4/7] [rtsan] Update notify function name in blocking Pass
---
llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp | 6 +++---
llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index c3ea1471796bdf..f27cf83cd3cf3d 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -52,7 +52,7 @@ static PreservedAnalyses rtsanPreservedCFGAnalyses() {
return PA;
}
-static void insertExpectNotRealtimeAtFunctionEntryPoint(Function &F) {
+static void insertNotifyBlockingCallAtFunctionEntryPoint(Function &F) {
IRBuilder<> Builder(&F.front().front());
Value *NameArg = Builder.CreateGlobalString(demangle(F.getName()));
@@ -61,7 +61,7 @@ static void insertExpectNotRealtimeAtFunctionEntryPoint(Function &F) {
{PointerType::getUnqual(F.getContext())}, false);
FunctionCallee Func = F.getParent()->getOrInsertFunction(
- "__rtsan_expect_not_realtime", FuncType);
+ "__rtsan_notify_blocking_call", FuncType);
Builder.CreateCall(Func, {NameArg});
}
@@ -78,7 +78,7 @@ PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
}
if (F.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
- insertExpectNotRealtimeAtFunctionEntryPoint(F);
+ insertNotifyBlockingCallAtFunctionEntryPoint(F);
return rtsanPreservedCFGAnalyses();
}
diff --git a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
index 0df01b95a79aea..fe9f13778e35af 100644
--- a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
@@ -16,4 +16,4 @@ attributes #0 = { mustprogress noinline sanitize_realtime_unsafe optnone ssp uwt
; CHECK: [[GLOBAL_STR:@[a-zA-Z0-9\.]+]]
; CHECK-SAME: c"blocking_function()\00"
; CHECK-LABEL: @_Z17blocking_functionv()
-; CHECK-NEXT: call{{.*}}@__rtsan_expect_not_realtime(ptr{{.*}}[[GLOBAL_STR]])
+; CHECK-NEXT: call{{.*}}@__rtsan_notify_blocking_call(ptr{{.*}}[[GLOBAL_STR]])
>From e8dad4ce774d4a5b19a9112e8b6476c2e8df15ff Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Tue, 24 Sep 2024 16:58:16 +0100
Subject: [PATCH 5/7] [rtsan][NFC] Update test comment and variable names
---
.../Instrumentation/RealtimeSanitizer.cpp | 24 +++++++++----------
.../RealtimeSanitizer/rtsan_unsafe.ll | 4 ++--
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index f27cf83cd3cf3d..3885fe049adc02 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -52,15 +52,15 @@ static PreservedAnalyses rtsanPreservedCFGAnalyses() {
return PA;
}
-static void insertNotifyBlockingCallAtFunctionEntryPoint(Function &F) {
- IRBuilder<> Builder(&F.front().front());
- Value *NameArg = Builder.CreateGlobalString(demangle(F.getName()));
+static void insertNotifyBlockingCallAtFunctionEntryPoint(Function &Fn) {
+ IRBuilder<> Builder(&Fn.front().front());
+ Value *NameArg = Builder.CreateGlobalString(demangle(Fn.getName()));
FunctionType *FuncType =
- FunctionType::get(Type::getVoidTy(F.getContext()),
- {PointerType::getUnqual(F.getContext())}, false);
+ FunctionType::get(Type::getVoidTy(Fn.getContext()),
+ {PointerType::getUnqual(Fn.getContext())}, false);
- FunctionCallee Func = F.getParent()->getOrInsertFunction(
+ FunctionCallee Func = Fn.getParent()->getOrInsertFunction(
"__rtsan_notify_blocking_call", FuncType);
Builder.CreateCall(Func, {NameArg});
@@ -69,16 +69,16 @@ static void insertNotifyBlockingCallAtFunctionEntryPoint(Function &F) {
RealtimeSanitizerPass::RealtimeSanitizerPass(
const RealtimeSanitizerOptions &Options) {}
-PreservedAnalyses RealtimeSanitizerPass::run(Function &F,
+PreservedAnalyses RealtimeSanitizerPass::run(Function &Fn,
AnalysisManager<Function> &AM) {
- if (F.hasFnAttribute(Attribute::SanitizeRealtime)) {
- insertCallAtFunctionEntryPoint(F, "__rtsan_realtime_enter");
- insertCallAtAllFunctionExitPoints(F, "__rtsan_realtime_exit");
+ if (Fn.hasFnAttribute(Attribute::SanitizeRealtime)) {
+ insertCallAtFunctionEntryPoint(Fn, "__rtsan_realtime_enter");
+ insertCallAtAllFunctionExitPoints(Fn, "__rtsan_realtime_exit");
return rtsanPreservedCFGAnalyses();
}
- if (F.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
- insertNotifyBlockingCallAtFunctionEntryPoint(F);
+ if (Fn.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
+ insertNotifyBlockingCallAtFunctionEntryPoint(Fn);
return rtsanPreservedCFGAnalyses();
}
diff --git a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
index fe9f13778e35af..68d9e0b195ba46 100644
--- a/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
+++ b/llvm/test/Instrumentation/RealtimeSanitizer/rtsan_unsafe.ll
@@ -11,8 +11,8 @@ define noundef i32 @main() #2 {
attributes #0 = { mustprogress noinline sanitize_realtime_unsafe optnone ssp uwtable(sync) }
-; RealtimeSanitizer pass should create the demangled function name as a global string, and
-; pass it as input to an inserted __rtsan_expect_not_realtime call at the function entrypoint
+; RealtimeSanitizer pass should create the demangled function name as a global string and,
+; at the function entrypoint, pass it as an argument to the rtsan notify method
; CHECK: [[GLOBAL_STR:@[a-zA-Z0-9\.]+]]
; CHECK-SAME: c"blocking_function()\00"
; CHECK-LABEL: @_Z17blocking_functionv()
>From 4dbd4e96299be0951d6001f54c8cc2b44abc5d59 Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Tue, 24 Sep 2024 17:23:14 +0100
Subject: [PATCH 6/7] [LLVM][rtsan] Refactor rtsan pass for code re-use
---
.../Instrumentation/RealtimeSanitizer.cpp | 63 ++++++++++---------
1 file changed, 35 insertions(+), 28 deletions(-)
diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index 3885fe049adc02..fd68f43f882540 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -20,30 +20,43 @@
#include "llvm/Demangle/Demangle.h"
#include "llvm/Transforms/Instrumentation/RealtimeSanitizer.h"
+#include <vector>
+
using namespace llvm;
+static std::vector<Type *> getArgTypes(ArrayRef<Value *> FunctionArgs) {
+ std::vector<Type *> Types;
+ for (Value *Arg : FunctionArgs)
+ Types.push_back(Arg->getType());
+ return Types;
+}
+
static void insertCallBeforeInstruction(Function &Fn, Instruction &Instruction,
- const char *FunctionName) {
+ const char *FunctionName,
+ ArrayRef<Value *> FunctionArgs) {
LLVMContext &Context = Fn.getContext();
- FunctionType *FuncType = FunctionType::get(Type::getVoidTy(Context), false);
+ FunctionType *FuncType = FunctionType::get(Type::getVoidTy(Context),
+ getArgTypes(FunctionArgs), false);
FunctionCallee Func =
Fn.getParent()->getOrInsertFunction(FunctionName, FuncType);
IRBuilder<> Builder{&Instruction};
- Builder.CreateCall(Func, {});
+ Builder.CreateCall(Func, FunctionArgs);
}
static void insertCallAtFunctionEntryPoint(Function &Fn,
- const char *InsertFnName) {
-
- insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName);
+ const char *InsertFnName,
+ ArrayRef<Value *> FunctionArgs) {
+ insertCallBeforeInstruction(Fn, Fn.front().front(), InsertFnName,
+ FunctionArgs);
}
static void insertCallAtAllFunctionExitPoints(Function &Fn,
- const char *InsertFnName) {
+ const char *InsertFnName,
+ ArrayRef<Value *> FunctionArgs) {
for (auto &BB : Fn)
for (auto &I : BB)
if (isa<ReturnInst>(&I))
- insertCallBeforeInstruction(Fn, I, InsertFnName);
+ insertCallBeforeInstruction(Fn, I, InsertFnName, FunctionArgs);
}
static PreservedAnalyses rtsanPreservedCFGAnalyses() {
@@ -52,18 +65,17 @@ static PreservedAnalyses rtsanPreservedCFGAnalyses() {
return PA;
}
-static void insertNotifyBlockingCallAtFunctionEntryPoint(Function &Fn) {
- IRBuilder<> Builder(&Fn.front().front());
- Value *NameArg = Builder.CreateGlobalString(demangle(Fn.getName()));
-
- FunctionType *FuncType =
- FunctionType::get(Type::getVoidTy(Fn.getContext()),
- {PointerType::getUnqual(Fn.getContext())}, false);
-
- FunctionCallee Func = Fn.getParent()->getOrInsertFunction(
- "__rtsan_notify_blocking_call", FuncType);
+static PreservedAnalyses runSanitizeRealtime(Function &Fn) {
+ insertCallAtFunctionEntryPoint(Fn, "__rtsan_realtime_enter", {});
+ insertCallAtAllFunctionExitPoints(Fn, "__rtsan_realtime_exit", {});
+ return rtsanPreservedCFGAnalyses();
+}
- Builder.CreateCall(Func, {NameArg});
+static PreservedAnalyses runSanitizeRealtimeUnsafe(Function &Fn) {
+ IRBuilder<> Builder(&Fn.front().front());
+ Value *Name = Builder.CreateGlobalString(demangle(Fn.getName()));
+ insertCallAtFunctionEntryPoint(Fn, "__rtsan_notify_blocking_call", {Name});
+ return rtsanPreservedCFGAnalyses();
}
RealtimeSanitizerPass::RealtimeSanitizerPass(
@@ -71,16 +83,11 @@ RealtimeSanitizerPass::RealtimeSanitizerPass(
PreservedAnalyses RealtimeSanitizerPass::run(Function &Fn,
AnalysisManager<Function> &AM) {
- if (Fn.hasFnAttribute(Attribute::SanitizeRealtime)) {
- insertCallAtFunctionEntryPoint(Fn, "__rtsan_realtime_enter");
- insertCallAtAllFunctionExitPoints(Fn, "__rtsan_realtime_exit");
- return rtsanPreservedCFGAnalyses();
- }
+ if (Fn.hasFnAttribute(Attribute::SanitizeRealtime))
+ return runSanitizeRealtime(Fn);
- if (Fn.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe)) {
- insertNotifyBlockingCallAtFunctionEntryPoint(Fn);
- return rtsanPreservedCFGAnalyses();
- }
+ if (Fn.hasFnAttribute(Attribute::SanitizeRealtimeUnsafe))
+ return runSanitizeRealtimeUnsafe(Fn);
return PreservedAnalyses::all();
}
>From f19d63dd904ec987155a92233de6be73cd5c6fe8 Mon Sep 17 00:00:00 2001
From: David Trevelyan <david.trevelyan at gmail.com>
Date: Tue, 24 Sep 2024 18:08:36 +0100
Subject: [PATCH 7/7] [LLVM][rtsan] Reserve space for types vector in pass
---
llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
index fd68f43f882540..49e1ab17effe8f 100644
--- a/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/RealtimeSanitizer.cpp
@@ -26,6 +26,7 @@ using namespace llvm;
static std::vector<Type *> getArgTypes(ArrayRef<Value *> FunctionArgs) {
std::vector<Type *> Types;
+ Types.reserve(FunctionArgs.size());
for (Value *Arg : FunctionArgs)
Types.push_back(Arg->getType());
return Types;
More information about the llvm-commits
mailing list