commit cfe40606f8bcc8d5e861f7e96d77258580498f71
Author: Jonathan Schleifer <js@webkeks.org>
Date:   Sat May 19 17:39:58 2012 +0200

    Add -fobjfw-runtime.
    
    Currently, this is based on CGObjCGCC, but uses direct class references.

diff --git a/include/clang/Basic/LangOptions.def b/include/clang/Basic/LangOptions.def
index a795c57..78e0559 100644
--- a/include/clang/Basic/LangOptions.def
+++ b/include/clang/Basic/LangOptions.def
@@ -81,6 +81,7 @@ LANGOPT(TraditionalCPP    , 1, 0, "traditional CPP emulation")
 LANGOPT(RTTI              , 1, 1, "run-time type information")
 LANGOPT(MSBitfields       , 1, 0, "Microsoft-compatible structure layout")
 LANGOPT(NeXTRuntime       , 1, 1, "NeXT Objective-C runtime")
+LANGOPT(ObjFWRuntime      , 1, 0, "ObjFW runtime")
 LANGOPT(Freestanding, 1, 0, "freestanding implementation")
 LANGOPT(NoBuiltin         , 1, 0, "disable builtin functions")
 
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 48f2b1a..080eb20 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -416,6 +416,7 @@ def fgnu89_inline : Flag<"-fgnu89-inline">, Group<f_Group>, Flags<[CC1Option]>,
 def fno_gnu89_inline : Flag<"-fno-gnu89-inline">, Group<f_Group>;
 def fgnu_runtime : Flag<"-fgnu-runtime">, Group<f_Group>, Flags<[CC1Option]>,
   HelpText<"Generate output compatible with the standard GNU Objective-C runtime">;
+def fobjfw_runtime: Flag<"-fobjfw-runtime">, Group<f_Group>, Flags<[CC1Option]>;
 def fheinous_gnu_extensions : Flag<"-fheinous-gnu-extensions">, Flags<[CC1Option]>;
 def filelist : Separate<"-filelist">, Flags<[LinkerInput]>;
 def findirect_virtual_calls : Flag<"-findirect-virtual-calls">, Alias<fapple_kext>;
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index e783eb7..3351f21 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -99,8 +99,8 @@ class LazyRuntimeFunction {
 
 
 /// GNU Objective-C runtime code generation.  This class implements the parts of
-/// Objective-C support that are specific to the GNU family of runtimes (GCC and
-/// GNUstep).
+/// Objective-C support that are specific to the GNU family of runtimes (GCC,
+/// GNUstep and ObjFW).
 class CGObjCGNU : public CGObjCRuntime {
 protected:
   /// The LLVM module into which output is inserted
@@ -395,13 +395,13 @@ private:
   /// Returns the variable used to store the offset of an instance variable.
   llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
       const ObjCIvarDecl *Ivar);
+protected:
   /// Emits a reference to a class.  This allows the linker to object if there
   /// is no class of the matching name.
   void EmitClassRef(const std::string &className);
   /// Emits a pointer to the named class
-  llvm::Value *GetClassNamed(CGBuilderTy &Builder, const std::string &Name,
-                             bool isWeak);
-protected:
+  virtual llvm::Value *GetClassNamed(CGBuilderTy &Builder,
+                                     const std::string &Name, bool isWeak);
   /// Looks up the method for sending a message to the specified object.  This
   /// mechanism differs between the GCC and GNU runtimes, so this method must be
   /// overridden in subclasses.
@@ -654,6 +654,30 @@ class CGObjCGNUstep : public CGObjCGNU {
 };
 
 } // end anonymous namespace
+/// Class used when targeting the ObjFW runtime ABI.
+class CGObjCObjFW : public CGObjCGCC {
+  virtual llvm::Value *GetClassNamed(CGBuilderTy &Builder,
+                                     const std::string &Name, bool isWeak) {
+    if (isWeak)
+      return CGObjCGNU::GetClassNamed(Builder, Name, isWeak);
+
+    EmitClassRef(Name);
+
+    std::string symbolName = "_OBJC_CLASS_" + Name;
+
+    llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(symbolName);
+    if (!ClassSymbol)
+      ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false,
+                                             llvm::GlobalValue::ExternalLinkage,
+                                             0, symbolName);
+
+    return ClassSymbol;
+  }
+
+  public:
+    CGObjCObjFW(CodeGenModule &Mod) : CGObjCGCC(Mod) {
+    }
+};
 
 
 /// Emits a reference to a dummy variable which is emitted with each class.
@@ -2669,3 +2693,9 @@ clang::CodeGen::CreateGNUObjCRuntime(CodeGenModule &CGM) {
     return new CGObjCGNUstep(CGM);
   return new CGObjCGCC(CGM);
 }
+
+CGObjCRuntime*
+clang::CodeGen::CreateObjFWObjCRuntime(CodeGenModule &CGM)
+{
+  return new CGObjCObjFW(CGM);
+}
diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h
index ccf4d4d..684290a 100644
--- a/lib/CodeGen/CGObjCRuntime.h
+++ b/lib/CodeGen/CGObjCRuntime.h
@@ -281,6 +281,7 @@ public:
 //TODO: This should include some way of selecting which runtime to target.
 CGObjCRuntime *CreateGNUObjCRuntime(CodeGenModule &CGM);
 CGObjCRuntime *CreateMacObjCRuntime(CodeGenModule &CGM);
+CGObjCRuntime *CreateObjFWObjCRuntime(CodeGenModule &CGM);
 }
 }
 #endif
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index f2dda5d..2ee9897 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -135,10 +135,12 @@ CodeGenModule::~CodeGenModule() {
 }
 
 void CodeGenModule::createObjCRuntime() {
-  if (!LangOpts.NeXTRuntime)
-    ObjCRuntime = CreateGNUObjCRuntime(*this);
-  else
+  if (LangOpts.ObjFWRuntime)
+    ObjCRuntime = CreateObjFWObjCRuntime(*this);
+  else if (LangOpts.NeXTRuntime)
     ObjCRuntime = CreateMacObjCRuntime(*this);
+  else
+    ObjCRuntime = CreateGNUObjCRuntime(*this);
 }
 
 void CodeGenModule::createOpenCLRuntime() {
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 1769077..092100d 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -2245,7 +2245,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
          !Args.hasArg(options::OPT_fno_blocks))) {
     CmdArgs.push_back("-fblocks");
 
-    if (!Args.hasArg(options::OPT_fgnu_runtime) && 
+    if (!Args.hasArg(options::OPT_fgnu_runtime) &&
         !getToolChain().hasBlocksRuntime())
       CmdArgs.push_back("-fblocks-runtime-optional");
   }
@@ -2365,8 +2365,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   bool NeXTRuntimeIsDefault
     = (IsRewriter || IsModernRewriter ||
        getToolChain().getTriple().isOSDarwin());
-  if (Args.hasFlag(options::OPT_fnext_runtime, options::OPT_fgnu_runtime,
-                   NeXTRuntimeIsDefault)) {
+  if (Args.hasFlag(options::OPT_fobjfw_runtime,
+                   options::OPT_fnext_runtime, 0)) {
+    CmdArgs.push_back("-fobjfw-runtime");
+    objCRuntime.setKind(ObjCRuntime::GNU);
+  } else if (Args.hasFlag(options::OPT_fnext_runtime,
+                          options::OPT_fgnu_runtime, NeXTRuntimeIsDefault)) {
     objCRuntime.setKind(ObjCRuntime::NeXT);
   } else {
     CmdArgs.push_back("-fgnu-runtime");
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 3a7efbc..54c6561 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -705,8 +705,10 @@ static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) {
     Res.push_back("-fno-rtti");
   if (Opts.MSBitfields)
     Res.push_back("-mms-bitfields");
-  if (!Opts.NeXTRuntime)
+  if (!Opts.NeXTRuntime && !Opts.ObjFWRuntime)
     Res.push_back("-fgnu-runtime");
+  if (Opts.ObjFWRuntime)
+    Res.push_back("-fobjfw-runtime");
   if (Opts.Freestanding)
     Res.push_back("-ffreestanding");
   if (Opts.NoBuiltin)
@@ -1948,6 +1950,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
                                                     0, Diags);
   Opts.MSBitfields = Args.hasArg(OPT_mms_bitfields);
   Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
+  Opts.ObjFWRuntime = Args.hasArg(OPT_fobjfw_runtime);
   Opts.ObjCConstantStringClass =
     Args.getLastArgValue(OPT_fconstant_string_class);
   Opts.ObjCNonFragileABI = !Args.hasArg(OPT_fobjc_fragile_abi);
