Hi,

Here is the resubmitting of x32 psABI[1] patches against the latest
trunk for code review after the patches[2] to LLVM.

* 0001-add-x32-psABI-support.patch
  add x32 psABI support

* 0002-revise-codegen-test-for-x32-psABI.patch
  revise/add codegen test for x32 psABI

Looking forward to your comments.

Thanks
- Michael

------
[1] https://sites.google.com/site/x32abi/
[2]
http://lists.cs.uiuc.edu/pipermail/llvm-commits/Week-of-Mon-20120709/146180.html
>From c4db8d7ad3f8c918a072707d6ad7e66ebc81564b Mon Sep 17 00:00:00 2001
From: Michael Liao <[email protected]>
Date: Mon, 2 Jul 2012 22:58:27 -0700
Subject: [PATCH 1/2] add x32 psABI support

- add '-mx32' option
- add linker/gcc-runtime support for x32 psABI

under x86-64 target, based on whether x32 psABI is turned on or off
- populate '_ILP32'/'__ILP32__' or '_LP64/__LP64__'
- set correct widths for data types
- add special handling of sret where pointer types could be packed
  with other 32-bit integer types into a single register
- detect target directly from target arch from target triple instead of
  pointer width
---
 include/clang/Driver/Options.td |    1 +
 lib/Basic/Targets.cpp           |   45 ++++++++++++++++++++++++++-------------
 lib/CodeGen/TargetInfo.cpp      |   25 ++++++++++++++--------
 lib/Driver/Driver.cpp           |    3 +++
 lib/Driver/ToolChains.cpp       |   13 ++++++-----
 lib/Driver/ToolChains.h         |    2 +-
 lib/Driver/Tools.cpp            |   13 ++++++++---
 7 files changed, 69 insertions(+), 33 deletions(-)

diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index a68353a..235d7a5 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -756,6 +756,7 @@ def mqdsp6_compat : Flag<"-mqdsp6-compat">, Group<m_Group>, Flags<[DriverOption,
   HelpText<"Enable hexagon-qdsp6 backward compatibility">;
 def m3dnowa : Flag<"-m3dnowa">, Group<m_x86_Features_Group>;
 def m3dnow : Flag<"-m3dnow">, Group<m_x86_Features_Group>;
+def mx32 : Flag<"-mx32">, Group<m_Group>, Flags<[DriverOption]>;
 def m64 : Flag<"-m64">, Group<m_Group>, Flags<[DriverOption]>;
 def mabi_EQ : Joined<"-mabi=">, Group<m_Group>;
 def march_EQ : Joined<"-march=">, Group<m_Group>;
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 5165193..1fc9862 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -1520,9 +1520,9 @@ public:
   virtual bool hasFeature(StringRef Feature) const;
   virtual void HandleTargetFeatures(std::vector<std::string> &Features);
   virtual const char* getABI() const {
-    if (PointerWidth == 64 && SSELevel >= AVX)
+    if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX)
       return "avx";
-    else if (PointerWidth == 32 && MMX3DNowLevel == NoMMX3DNow)
+    else if (getTriple().getArch() == llvm::Triple::x86 && MMX3DNowLevel == NoMMX3DNow)
       return "no-mmx";
     return "";
   }
@@ -1616,7 +1616,7 @@ public:
     case CK_AthlonMP:
     case CK_Geode:
       // Only accept certain architectures when compiling in 32-bit mode.
-      if (PointerWidth != 32)
+      if (getTriple().getArch() != llvm::Triple::x86)
         return false;
 
       // Fallthrough
@@ -1674,7 +1674,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
   // FIXME: This *really* should not be here.
 
   // X86_64 always has SSE2.
-  if (PointerWidth == 64)
+  if (getTriple().getArch() == llvm::Triple::x86_64)
     Features["sse2"] = Features["sse"] = Features["mmx"] = true;
 
   switch (CPU) {
@@ -2047,10 +2047,14 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) {
 void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
                                      MacroBuilder &Builder) const {
   // Target identification.
-  if (PointerWidth == 64) {
-    if (getLongWidth() == 64) {
+  if (getTriple().getArch() == llvm::Triple::x86_64) {
+    if (PointerWidth == 64 && getLongWidth() == 64) {
       Builder.defineMacro("_LP64");
       Builder.defineMacro("__LP64__");
+    } else if (PointerWidth == 32 && getLongWidth() == 32 &&
+               getIntWidth() == 32) {
+      Builder.defineMacro("_ILP32");
+      Builder.defineMacro("__ILP32__");
     }
     Builder.defineMacro("__amd64__");
     Builder.defineMacro("__amd64");
@@ -2303,8 +2307,8 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
       .Case("sse42", SSELevel >= SSE42)
       .Case("sse4a", HasSSE4a)
       .Case("x86", true)
-      .Case("x86_32", PointerWidth == 32)
-      .Case("x86_64", PointerWidth == 64)
+      .Case("x86_32", getTriple().getArch() == llvm::Triple::x86)
+      .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64)
       .Case("xop", HasXOP)
       .Default(false);
 }
@@ -2634,20 +2638,31 @@ namespace {
 class X86_64TargetInfo : public X86TargetInfo {
 public:
   X86_64TargetInfo(const std::string &triple) : X86TargetInfo(triple) {
-    LongWidth = LongAlign = PointerWidth = PointerAlign = 64;
+    const bool IsX32 = (getTriple().getEnvironment() == llvm::Triple::X32);
+    LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64;
     LongDoubleWidth = 128;
     LongDoubleAlign = 128;
     LargeArrayMinWidth = 128;
     LargeArrayAlign = 128;
     SuitableAlign = 128;
-    IntMaxType = SignedLong;
-    UIntMaxType = UnsignedLong;
-    Int64Type = SignedLong;
+    if (IsX32) {
+      SizeType = UnsignedInt;
+      PtrDiffType = SignedInt;
+      IntPtrType = SignedInt;
+    } else {
+      IntMaxType = SignedLong;
+      UIntMaxType = UnsignedLong;
+      Int64Type = SignedLong;
+    }
     RegParmMax = 6;
 
-    DescriptionString = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
-                        "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
-                        "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128";
+    DescriptionString = IsX32 ?
+      "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+      "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
+      "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" :
+      "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-"
+      "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-"
+      "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128";
 
     // Use fpret only for long double.
     RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble);
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index 1ff7ed0..b72b20f 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -954,9 +954,11 @@ class X86_64ABIInfo : public ABIInfo {
 
   bool HasAVX;
 
+  bool isX32; // X32 psABI
+
 public:
-  X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool hasavx) :
-      ABIInfo(CGT), HasAVX(hasavx) {}
+  X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool hasavx, bool IsX32) :
+      ABIInfo(CGT), HasAVX(hasavx), isX32(IsX32) {}
 
   bool isPassedUsingAVXType(QualType type) const {
     unsigned neededInt, neededSSE;
@@ -992,8 +994,8 @@ public:
 
 class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
 public:
-  X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX)
-    : TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX)) {}
+  X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX, bool IsX32)
+    : TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX, IsX32)) {}
 
   const X86_64ABIInfo &getABIInfo() const {
     return static_cast<const X86_64ABIInfo&>(TargetCodeGenInfo::getABIInfo());
@@ -1189,7 +1191,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
   }
 
   if (Ty->isMemberPointerType()) {
-    if (Ty->isMemberFunctionPointerType())
+    if (Ty->isMemberFunctionPointerType() && !isX32)
       Lo = Hi = Integer;
     else
       Current = Integer;
@@ -1700,7 +1702,7 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
   // returning an 8-byte unit starting with it.  See if we can safely use it.
   if (IROffset == 0) {
     // Pointers and int64's always fill the 8-byte unit.
-    if (isa<llvm::PointerType>(IRType) || IRType->isIntegerTy(64))
+    if ((!isX32 && isa<llvm::PointerType>(IRType)) || IRType->isIntegerTy(64))
       return IRType;
 
     // If we have a 1/2/4-byte integer, we can use it only if the rest of the
@@ -1709,9 +1711,12 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset,
     // struct{double,int,int} because we wouldn't return the second int.  We
     // have to do this analysis on the source type because we can't depend on
     // unions being lowered a specific way etc.
-    if (IRType->isIntegerTy(8) || IRType->isIntegerTy(16) ||
+    if ((isX32 && isa<llvm::PointerType>(IRType)) ||
+        IRType->isIntegerTy(8) || IRType->isIntegerTy(16) ||
         IRType->isIntegerTy(32)) {
-      unsigned BitWidth = cast<llvm::IntegerType>(IRType)->getBitWidth();
+      unsigned BitWidth = 32;
+      if (!isa<llvm::PointerType>(IRType))
+        BitWidth = cast<llvm::IntegerType>(IRType)->getBitWidth();
 
       if (BitsContainNoUserData(SourceTy, SourceOffset*8+BitWidth,
                                 SourceOffset*8+64, getContext()))
@@ -3761,6 +3766,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
 
   case llvm::Triple::x86_64: {
     bool HasAVX = strcmp(getContext().getTargetInfo().getABI(), "avx") == 0;
+    bool IsX32 = Triple.getEnvironment() == llvm::Triple::X32;
 
     switch (Triple.getOS()) {
     case llvm::Triple::Win32:
@@ -3769,7 +3775,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
       return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types));
     default:
       return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types,
-                                                                  HasAVX));
+                                                                  HasAVX,
+                                                                  IsX32));
     }
   }
   case llvm::Triple::hexagon:
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index a2afb76..dc6edbb 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -1708,6 +1708,9 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple,
       if (Target.getArch() == llvm::Triple::ppc)
         Target.setArch(llvm::Triple::ppc64);
     }
+  } else if (Args.getLastArg(options::OPT_mx32)) {
+    if (Target.getArch() == llvm::Triple::x86_64)
+      Target.setEnvironment(llvm::Triple::X32);
   }
 
   return Target;
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 93df747..51dc80c 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -1029,7 +1029,6 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
   llvm::Triple MultiarchTriple
     = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant()
                                  : TargetTriple.get32BitArchVariant();
-  llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
   // The library directories which may contain GCC installations.
   SmallVector<StringRef, 4> CandidateLibDirs, CandidateMultiarchLibDirs;
   // The compatible GCC triples for this particular architecture.
@@ -1067,7 +1066,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
       if (!llvm::sys::fs::exists(LibDir))
         continue;
       for (unsigned k = 0, ke = CandidateTripleAliases.size(); k < ke; ++k)
-        ScanLibDirForGCCTriple(TargetArch, LibDir, CandidateTripleAliases[k]);
+        ScanLibDirForGCCTriple(TargetTriple, LibDir, CandidateTripleAliases[k]);
     }
     for (unsigned j = 0, je = CandidateMultiarchLibDirs.size(); j < je; ++j) {
       const std::string LibDir
@@ -1076,7 +1075,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
         continue;
       for (unsigned k = 0, ke = CandidateMultiarchTripleAliases.size(); k < ke;
            ++k)
-        ScanLibDirForGCCTriple(TargetArch, LibDir,
+        ScanLibDirForGCCTriple(TargetTriple, LibDir,
                                CandidateMultiarchTripleAliases[k],
                                /*NeedsMultiarchSuffix=*/true);
     }
@@ -1252,8 +1251,9 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
 }
 
 void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
-    llvm::Triple::ArchType TargetArch, const std::string &LibDir,
+    llvm::Triple TargetTriple, const std::string &LibDir,
     StringRef CandidateTriple, bool NeedsMultiarchSuffix) {
+  llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
   // There are various different suffixes involving the triple we
   // check for. We also record what is necessary to walk from each back
   // up to the lib directory.
@@ -1299,6 +1299,8 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
            TargetArch == llvm::Triple::ppc64 ||
            TargetArch == llvm::Triple::mips64 ||
            TargetArch == llvm::Triple::mips64el) ? "/64" : "/32";
+      if (TargetTriple.getEnvironment() == llvm::Triple::X32)
+        MultiarchSuffix = "/x32";
       if (llvm::sys::fs::exists(LI->path() + MultiarchSuffix + "/crtbegin.o")) {
         GCCMultiarchSuffix = MultiarchSuffix.str();
       } else {
@@ -2000,7 +2002,8 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
   // to the link paths.
   path_list &Paths = getFilePaths();
 
-  const std::string Multilib = Triple.isArch32Bit() ? "lib32" : "lib64";
+  const bool IsX32 = getTriple().getEnvironment() == llvm::Triple::X32;
+  const std::string Multilib = Triple.isArch32Bit() ? "lib32" : IsX32 ? "libx32" : "lib64";
   const std::string MultiarchTriple = getMultiarchTriple(Triple, SysRoot);
 
   // Add the multilib suffixed paths where they are available.
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index 7c163a0..bcb3300 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -110,7 +110,7 @@ protected:
       SmallVectorImpl<StringRef> &MultiarchLibDirs,
       SmallVectorImpl<StringRef> &MultiarchTripleAliases);
 
-    void ScanLibDirForGCCTriple(llvm::Triple::ArchType TargetArch,
+    void ScanLibDirForGCCTriple(llvm::Triple TargetTriple,
                                 const std::string &LibDir,
                                 StringRef CandidateTriple,
                                 bool NeedsMultiarchSuffix = false);
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 66d792f..f2f8670 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -5452,7 +5452,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
   if (ToolChain.getArch() == llvm::Triple::x86)
     CmdArgs.push_back("elf_i386");
   else if (ToolChain.getArch() == llvm::Triple::arm
-           ||  ToolChain.getArch() == llvm::Triple::thumb)
+           || ToolChain.getArch() == llvm::Triple::thumb)
     CmdArgs.push_back("armelf_linux_eabi");
   else if (ToolChain.getArch() == llvm::Triple::ppc)
     CmdArgs.push_back("elf32ppclinux");
@@ -5466,8 +5466,12 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
     CmdArgs.push_back("elf64btsmip");
   else if (ToolChain.getArch() == llvm::Triple::mips64el)
     CmdArgs.push_back("elf64ltsmip");
+  else if (ToolChain.getArch() == llvm::Triple::x86_64)
+    CmdArgs.push_back(ToolChain.getTriple().getEnvironment() ==
+                      llvm::Triple::X32
+                      ? "elf32_x86_64" : "elf_x86_64");
   else
-    CmdArgs.push_back("elf_x86_64");
+    llvm_unreachable("unknown arch");
 
   if (Args.hasArg(options::OPT_static)) {
     if (ToolChain.getArch() == llvm::Triple::arm
@@ -5506,7 +5510,10 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA,
     else if (ToolChain.getArch() == llvm::Triple::ppc64)
       CmdArgs.push_back("/lib64/ld64.so.1");
     else
-      CmdArgs.push_back("/lib64/ld-linux-x86-64.so.2");
+      CmdArgs.push_back(ToolChain.getTriple().getEnvironment() ==
+                        llvm::Triple::X32
+                        ? "/libx32/ld-linux-x32.so.2"
+                        : "/lib64/ld-linux-x86-64.so.2");
   }
 
   CmdArgs.push_back("-o");
-- 
1.7.9.5

>From b1aa68fd41abd351d6c37019286ff0ec1ebde4a1 Mon Sep 17 00:00:00 2001
From: Michael Liao <[email protected]>
Date: Mon, 2 Jul 2012 23:03:12 -0700
Subject: [PATCH 2/2] revise codegen test for x32 psABI

- revise/add test cases where x32ps ABI will generate different code
  due to pointer size change
---
 test/CodeGen/sret-x32.c         |   20 ++++++++++++++++++++
 test/CodeGen/sret.c             |    1 +
 test/CodeGen/sret2-x32.c        |   11 +++++++++++
 test/CodeGen/sret2.c            |    1 +
 test/CodeGen/x86_64-arguments.c |    3 +++
 5 files changed, 36 insertions(+)
 create mode 100644 test/CodeGen/sret-x32.c
 create mode 100644 test/CodeGen/sret2-x32.c

diff --git a/test/CodeGen/sret-x32.c b/test/CodeGen/sret-x32.c
new file mode 100644
index 0000000..690ed45
--- /dev/null
+++ b/test/CodeGen/sret-x32.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 %s -triple=x86_64-gnux32 -emit-llvm -O0 -o - | grep sret | count 1
+// RUN: %clang_cc1 %s -triple=x86_64-gnux32 -emit-llvm -O0 -o - | grep bitcast | count 2
+// RUN: %clang_cc1 %s -triple=x86_64-gnux32 -emit-llvm -O0 -o - | FileCheck %s
+
+struct abc {
+ long a;
+ long b;
+ long c;
+};
+ 
+struct abc foo1(void);
+struct abc foo2();
+
+void bar() {
+  struct abc dummy1 = foo1();
+  struct abc dummy2 = foo2();
+}
+
+// CHECK: declare { i64, i32 } @foo1()
+// CHECK: declare { i64, i32 } @foo2(...)
diff --git a/test/CodeGen/sret.c b/test/CodeGen/sret.c
index ed1f9a4..c67c548 100644
--- a/test/CodeGen/sret.c
+++ b/test/CodeGen/sret.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 %s -emit-llvm -O0 -o - | grep sret | count 5
+// XFAIL: x32
 
 struct abc {
  long a;
diff --git a/test/CodeGen/sret2-x32.c b/test/CodeGen/sret2-x32.c
new file mode 100644
index 0000000..f55f1a9
--- /dev/null
+++ b/test/CodeGen/sret2-x32.c
@@ -0,0 +1,11 @@
+// RUN: %clang_cc1 %s -triple=x86_64-gnux32 -emit-llvm -O0 -o - | grep bitcast | count 1
+// RUN: %clang_cc1 %s -triple=x86_64-gnux32 -emit-llvm -O0 -o - | FileCheck %s
+
+struct abc {
+ long a;
+ long b;
+ long c;
+};
+ 
+// CHECK: define { i64, i32 } @foo2()
+struct abc foo2(){}
diff --git a/test/CodeGen/sret2.c b/test/CodeGen/sret2.c
index c96ce4d..68da490 100644
--- a/test/CodeGen/sret2.c
+++ b/test/CodeGen/sret2.c
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 %s -emit-llvm -O0 -o - | grep sret | count 2
+// XFAIL: x32
 
 struct abc {
  long a;
diff --git a/test/CodeGen/x86_64-arguments.c b/test/CodeGen/x86_64-arguments.c
index f73e1f0..1942fb8 100644
--- a/test/CodeGen/x86_64-arguments.c
+++ b/test/CodeGen/x86_64-arguments.c
@@ -1,5 +1,6 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s| FileCheck %s
 // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s -target-feature +avx | FileCheck %s -check-prefix=AVX
+// RUN: %clang_cc1 -triple x86_64-gnux32 -emit-llvm -o - %s| FileCheck %s -check-prefix=X32ABI
 #include <stdarg.h>
 
 // CHECK: define signext i8 @f0()
@@ -120,6 +121,7 @@ struct StringRef {
 
 // rdar://7375902
 // CHECK: define i8* @f21(i64 %S.coerce0, i8* %S.coerce1) 
+// X32ABI: define i8* @f21(i64 %S.coerce)
 const char *f21(struct StringRef S) { return S.x+S.Ptr; }
 
 // PR7567
@@ -171,6 +173,7 @@ struct foo26 {
 
 struct foo26 f26(struct foo26 *P) {
   // CHECK: define { i32*, float* } @f26(%struct.foo26* %P)
+  // X32ABI: define i64 @f26(%struct.foo26* %P)
   return *P;
 }
 
-- 
1.7.9.5

_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to