]> granicus.if.org Git - clang/commitdiff
[PowerPC] Support ELFv1/ELFv2 ABI selection via -mabi= option
authorUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 28 Jul 2014 13:17:52 +0000 (13:17 +0000)
committerUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 28 Jul 2014 13:17:52 +0000 (13:17 +0000)
While Clang now supports both ELFv1 and ELFv2 ABIs, their use is currently
hard-coded via the target triple: powerpc64-linux is always ELFv1, while
powerpc64le-linux is always ELFv2.

These are of course the most common scenarios, but in principle it is
possible to support the ELFv2 ABI on big-endian or the ELFv1 ABI on
little-endian systems (and GCC does support that), and there are some
special use cases for that (e.g. certain Linux kernel versions could
only be built using ELFv1 on LE).

This patch implements the Clang side of supporting this, based on the
LLVM commit 214072.  The command line options -mabi=elfv1 or -mabi=elfv2
select the desired ABI if present.  (If not, Clang uses the same default
rules as now.)

Specifically, the patch implements the following changes based on the
presence of the -mabi= option:

In the driver:
- Pass the appropiate -target-abi flag to the back-end
- Select the correct dynamic loader version (/lib64/ld64.so.[12])

In the preprocessor:
- Define _CALL_ELF to the appropriate value (1 or 2)

In the compiler back-end:
- Select the correct ABI in TargetInfo.cpp
- Select the desired ABI for LLVM via feature (elfv1/elfv2)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@214074 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Basic/Targets.cpp
lib/CodeGen/TargetInfo.cpp
lib/Driver/Tools.cpp
lib/Driver/Tools.h
test/CodeGen/ppc64-elf-abi.c [new file with mode: 0644]
test/Driver/linux-ld.c
test/Driver/ppc-abi.c [new file with mode: 0644]
test/Preprocessor/init.c

index 3a80d0f2ac0a358416ebf6790f91c8f05d4ddc98..08d6bdd4d1524c4b890b917e28738403bc34ee66 100644 (file)
@@ -682,6 +682,9 @@ class PPCTargetInfo : public TargetInfo {
   // Target cpu features.
   bool HasVSX;
 
+protected:
+  std::string ABI;
+
 public:
   PPCTargetInfo(const llvm::Triple &Triple)
       : TargetInfo(Triple), HasVSX(false) {
@@ -770,6 +773,9 @@ public:
     return CPUKnown;
   }
 
+
+  StringRef getABI() const override { return ABI; }
+
   void getTargetBuiltins(const Builtin::Info *&Records,
                          unsigned &NumRecords) const override {
     Records = BuiltinInfo;
@@ -965,13 +971,18 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts,
   // Target properties.
   if (getTriple().getArch() == llvm::Triple::ppc64le) {
     Builder.defineMacro("_LITTLE_ENDIAN");
-    Builder.defineMacro("_CALL_ELF","2");
   } else {
     if (getTriple().getOS() != llvm::Triple::NetBSD &&
         getTriple().getOS() != llvm::Triple::OpenBSD)
       Builder.defineMacro("_BIG_ENDIAN");
   }
 
+  // ABI options.
+  if (ABI == "elfv1")
+    Builder.defineMacro("_CALL_ELF", "1");
+  if (ABI == "elfv2")
+    Builder.defineMacro("_CALL_ELF", "2");
+
   // Subtarget options.
   Builder.defineMacro("__NATURAL_ALIGNMENT__");
   Builder.defineMacro("__REGISTER_PREFIX__", "");
@@ -1121,6 +1132,9 @@ void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const {
     .Default(false);
 
   Features["qpx"] = (CPU == "a2q");
+
+  if (!ABI.empty())
+    Features[ABI] = true;
 }
 
 bool PPCTargetInfo::hasFeature(StringRef Feature) const {
@@ -1283,10 +1297,12 @@ public:
     } else {
       if ((Triple.getArch() == llvm::Triple::ppc64le)) {
         DescriptionString = "e-m:e-i64:64-n32:64";
+        ABI = "elfv2";
       } else {
         DescriptionString = "E-m:e-i64:64-n32:64";
+        ABI = "elfv1";
       }
-}
+    }
 
     // PPC64 supports atomics up to 8 bytes.
     MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
@@ -1294,6 +1310,14 @@ public:
   BuiltinVaListKind getBuiltinVaListKind() const override {
     return TargetInfo::CharPtrBuiltinVaList;
   }
+  // PPC64 Linux-specifc ABI options.
+  bool setABI(const std::string &Name) override {
+    if (Name == "elfv1" || Name == "elfv2") {
+      ABI = Name;
+      return true;
+    }
+    return false;
+  }
 };
 } // end anonymous namespace.
 
index 1a1ac8bd925944232d7a9f2e56b5688c5a27e9d9..ca99ba580a57ff5766964d039874d4f2c460a0f0 100644 (file)
@@ -6799,16 +6799,20 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
     return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo(Types));
   case llvm::Triple::ppc64:
     if (Triple.isOSBinFormatELF()) {
-      // FIXME: Should be switchable via command-line option.
       PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv1;
+      if (getTarget().getABI() == "elfv2")
+        Kind = PPC64_SVR4_ABIInfo::ELFv2;
+
       return *(TheTargetCodeGenInfo =
                new PPC64_SVR4_TargetCodeGenInfo(Types, Kind));
     } else
       return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types));
   case llvm::Triple::ppc64le: {
     assert(Triple.isOSBinFormatELF() && "PPC64 LE non-ELF not supported!");
-    // FIXME: Should be switchable via command-line option.
     PPC64_SVR4_ABIInfo::ABIKind Kind = PPC64_SVR4_ABIInfo::ELFv2;
+    if (getTarget().getABI() == "elfv1")
+      Kind = PPC64_SVR4_ABIInfo::ELFv1;
+
     return *(TheTargetCodeGenInfo =
              new PPC64_SVR4_TargetCodeGenInfo(Types, Kind));
   }
index 403642e736eb636f69b51305d415432c404e0e83..adbe09448914feea484735209abb3944ca134b59 100644 (file)
@@ -1228,6 +1228,35 @@ static void getPPCTargetFeatures(const ArgList &Args,
                    options::OPT_fno_altivec, "altivec");
 }
 
+void Clang::AddPPCTargetArgs(const ArgList &Args,
+                             ArgStringList &CmdArgs) const {
+  // Select the ABI to use.
+  const char *ABIName = nullptr;
+  if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
+    ABIName = A->getValue();
+  } else if (getToolChain().getTriple().isOSLinux())
+    switch(getToolChain().getArch()) {
+    case llvm::Triple::ppc64:
+      ABIName = "elfv1";
+      break;
+    case llvm::Triple::ppc64le:
+      ABIName = "elfv2";
+      break;
+    default:
+      break;
+  }
+
+  if (ABIName) {
+    CmdArgs.push_back("-target-abi");
+    CmdArgs.push_back(ABIName);
+  }
+}
+
+bool ppc::hasPPCAbiArg(const ArgList &Args, const char *Value) {
+  Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
+  return A && (A->getValue() == StringRef(Value));
+}
+
 /// Get the (LLVM) name of the R600 gpu we are targeting.
 static std::string getR600TargetGPU(const ArgList &Args) {
   if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
@@ -3021,6 +3050,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     AddMIPSTargetArgs(Args, CmdArgs);
     break;
 
+  case llvm::Triple::ppc:
+  case llvm::Triple::ppc64:
+  case llvm::Triple::ppc64le:
+    AddPPCTargetArgs(Args, CmdArgs);
+    break;
+
   case llvm::Triple::sparc:
   case llvm::Triple::sparcv9:
     AddSparcTargetArgs(Args, CmdArgs);
@@ -7212,11 +7247,16 @@ static StringRef getLinuxDynamicLinker(const ArgList &Args,
                ? "/lib64/ld-linux-mipsn8.so.1" : "/lib64/ld.so.1";
   } else if (ToolChain.getArch() == llvm::Triple::ppc)
     return "/lib/ld.so.1";
-  else if (ToolChain.getArch() == llvm::Triple::ppc64 ||
-           ToolChain.getArch() == llvm::Triple::systemz)
+  else if (ToolChain.getArch() == llvm::Triple::ppc64) {
+    if (ppc::hasPPCAbiArg(Args, "elfv2"))
+      return "/lib64/ld64.so.2";
     return "/lib64/ld64.so.1";
-  else if (ToolChain.getArch() == llvm::Triple::ppc64le)
+  } else if (ToolChain.getArch() == llvm::Triple::ppc64le) {
+    if (ppc::hasPPCAbiArg(Args, "elfv1"))
+      return "/lib64/ld64.so.1";
     return "/lib64/ld64.so.2";
+  } else if (ToolChain.getArch() == llvm::Triple::systemz)
+    return "/lib64/ld64.so.1";
   else if (ToolChain.getArch() == llvm::Triple::sparcv9)
     return "/lib64/ld-linux.so.2";
   else if (ToolChain.getArch() == llvm::Triple::x86_64 &&
index 4c89676e0e195897bddd929fc3b378c439b89ca6..1b3141117892e25c5635a64aa2b597b5cdb1874d 100644 (file)
@@ -63,6 +63,8 @@ using llvm::opt::ArgStringList;
                             llvm::opt::ArgStringList &CmdArgs) const;
     void AddMIPSTargetArgs(const llvm::opt::ArgList &Args,
                            llvm::opt::ArgStringList &CmdArgs) const;
+    void AddPPCTargetArgs(const llvm::opt::ArgList &Args,
+                          llvm::opt::ArgStringList &CmdArgs) const;
     void AddR600TargetArgs(const llvm::opt::ArgList &Args,
                            llvm::opt::ArgStringList &CmdArgs) const;
     void AddSparcTargetArgs(const llvm::opt::ArgList &Args,
@@ -226,6 +228,10 @@ namespace mips {
                      StringRef ABIName);
 }
 
+namespace ppc {
+  bool hasPPCAbiArg(const llvm::opt::ArgList &Args, const char *Value);
+}
+
 namespace darwin {
   llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str);
   void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str);
diff --git a/test/CodeGen/ppc64-elf-abi.c b/test/CodeGen/ppc64-elf-abi.c
new file mode 100644 (file)
index 0000000..0dd183e
--- /dev/null
@@ -0,0 +1,40 @@
+// REQUIRES: powerpc-registered-target
+
+// Verify ABI selection by the front end
+
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN:   | FileCheck %s --check-prefix=CHECK-ELFv1
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN:   -target-abi elfv1 | FileCheck %s --check-prefix=CHECK-ELFv1
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN:   -target-abi elfv2 | FileCheck %s --check-prefix=CHECK-ELFv2
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN:   | FileCheck %s --check-prefix=CHECK-ELFv2
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN:   -target-abi elfv1 | FileCheck %s --check-prefix=CHECK-ELFv1
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -emit-llvm -o - %s \
+// RUN:   -target-abi elfv2 | FileCheck %s --check-prefix=CHECK-ELFv2
+
+// CHECK-ELFv1: define void @func_fab(%struct.fab* noalias sret %agg.result, i64 %x.coerce)
+// CHECK-ELFv2: define [2 x float] @func_fab([2 x float] %x.coerce)
+struct fab { float a; float b; };
+struct fab func_fab(struct fab x) { return x; }
+
+// Verify ABI choice is passed on to the back end
+
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -S -o - %s \
+// RUN:   | FileCheck %s --check-prefix=CHECK-ASM-ELFv1
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -S -o - %s \
+// RUN:   -target-abi elfv1 | FileCheck %s --check-prefix=CHECK-ASM-ELFv1
+// RUN: %clang_cc1 -triple powerpc64-unknown-linux-gnu -S -o - %s \
+// RUN:   -target-abi elfv2 | FileCheck %s --check-prefix=CHECK-ASM-ELFv2
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -S -o - %s \
+// RUN:   | FileCheck %s --check-prefix=CHECK-ASM-ELFv2
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -S -o - %s \
+// RUN:   -target-abi elfv1 | FileCheck %s --check-prefix=CHECK-ASM-ELFv1
+// RUN: %clang_cc1 -triple powerpc64le-unknown-linux-gnu -S -o - %s \
+// RUN:   -target-abi elfv2 | FileCheck %s --check-prefix=CHECK-ASM-ELFv2
+
+// CHECK-ASM-ELFv2: .abiversion 2
+// CHECK-ASM-ELFv1-NOT: .abiversion 2
+
index 6a47d08274d2dd60fe2d58f74d994915004764ca..dbdaaa1e1c4a89d7a94152bf6555ad5fc6d5913c 100644 (file)
 // CHECK-ARM-HF: "-dynamic-linker" "{{.*}}/lib/ld-linux-armhf.so.3"
 //
 // RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN:     --target=powerpc64-linux-gnu \
+// RUN:   | FileCheck --check-prefix=CHECK-PPC64 %s
+// CHECK-PPC64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-PPC64: "-m" "elf64ppc"
+// CHECK-PPC64: "-dynamic-linker" "{{.*}}/lib64/ld64.so.1"
+//
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN:     --target=powerpc64-linux-gnu -mabi=elfv1 \
+// RUN:   | FileCheck --check-prefix=CHECK-PPC64-ELFv1 %s
+// CHECK-PPC64-ELFv1: "{{.*}}ld{{(.exe)?}}"
+// CHECK-PPC64-ELFv1: "-m" "elf64ppc"
+// CHECK-PPC64-ELFv1: "-dynamic-linker" "{{.*}}/lib64/ld64.so.1"
+//
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN:     --target=powerpc64-linux-gnu -mabi=elfv2 \
+// RUN:   | FileCheck --check-prefix=CHECK-PPC64-ELFv2 %s
+// CHECK-PPC64-ELFv2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-PPC64-ELFv2: "-m" "elf64ppc"
+// CHECK-PPC64-ELFv2: "-dynamic-linker" "{{.*}}/lib64/ld64.so.2"
+//
+// RUN: %clang %s -### -o %t.o 2>&1 \
 // RUN:     --target=powerpc64le-linux-gnu \
 // RUN:   | FileCheck --check-prefix=CHECK-PPC64LE %s
 // CHECK-PPC64LE: "{{.*}}ld{{(.exe)?}}"
 // CHECK-PPC64LE: "-m" "elf64lppc"
 // CHECK-PPC64LE: "-dynamic-linker" "{{.*}}/lib64/ld64.so.2"
 //
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN:     --target=powerpc64le-linux-gnu -mabi=elfv1 \
+// RUN:   | FileCheck --check-prefix=CHECK-PPC64LE-ELFv1 %s
+// CHECK-PPC64LE-ELFv1: "{{.*}}ld{{(.exe)?}}"
+// CHECK-PPC64LE-ELFv1: "-m" "elf64lppc"
+// CHECK-PPC64LE-ELFv1: "-dynamic-linker" "{{.*}}/lib64/ld64.so.1"
+//
+// RUN: %clang %s -### -o %t.o 2>&1 \
+// RUN:     --target=powerpc64le-linux-gnu -mabi=elfv2 \
+// RUN:   | FileCheck --check-prefix=CHECK-PPC64LE-ELFv2 %s
+// CHECK-PPC64LE-ELFv2: "{{.*}}ld{{(.exe)?}}"
+// CHECK-PPC64LE-ELFv2: "-m" "elf64lppc"
+// CHECK-PPC64LE-ELFv2: "-dynamic-linker" "{{.*}}/lib64/ld64.so.2"
+//
 // Check that we do not pass --hash-style=gnu and --hash-style=both to linker
 // and provide correct path to the dynamic linker and emulation mode when build
 // for MIPS platforms.
diff --git a/test/Driver/ppc-abi.c b/test/Driver/ppc-abi.c
new file mode 100644 (file)
index 0000000..6fee63a
--- /dev/null
@@ -0,0 +1,19 @@
+// Check passing PowerPC ABI options to the backend.
+
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -### -o %t.o 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHECK-ELFv1 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -### -o %t.o 2>&1 \
+// RUN:   -mabi=elfv1 | FileCheck -check-prefix=CHECK-ELFv1 %s
+// RUN: %clang -target powerpc64-unknown-linux-gnu %s -### -o %t.o 2>&1 \
+// RUN:   -mabi=elfv2 | FileCheck -check-prefix=CHECK-ELFv2 %s
+
+// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -o %t.o 2>&1 \
+// RUN:   | FileCheck -check-prefix=CHECK-ELFv2 %s
+// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -o %t.o 2>&1 \
+// RUN:   -mabi=elfv1 | FileCheck -check-prefix=CHECK-ELFv1 %s
+// RUN: %clang -target powerpc64le-unknown-linux-gnu %s -### -o %t.o 2>&1 \
+// RUN:   -mabi=elfv2 | FileCheck -check-prefix=CHECK-ELFv2 %s
+
+// CHECK-ELFv1: "-target-abi" "elfv1"
+// CHECK-ELFv2: "-target-abi" "elfv2"
+
index 48f586a7de34a500ad0235901d413c979c03894f..3342225ddc93277beb318eb42f85d3478b4ad32f 100644 (file)
 // PPC64-LINUX:#define __powerpc__ 1
 // PPC64-LINUX:#define __ppc64__ 1
 // PPC64-LINUX:#define __ppc__ 1
+
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-linux-gnu < /dev/null | FileCheck -check-prefix PPC64-ELFv1 %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-linux-gnu -target-abi elfv1 < /dev/null | FileCheck -check-prefix PPC64-ELFv1 %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64-unknown-linux-gnu -target-abi elfv2 < /dev/null | FileCheck -check-prefix PPC64-ELFv2 %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64le-unknown-linux-gnu < /dev/null | FileCheck -check-prefix PPC64-ELFv2 %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64le-unknown-linux-gnu -target-abi elfv1 < /dev/null | FileCheck -check-prefix PPC64-ELFv1 %s
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc64le-unknown-linux-gnu -target-abi elfv2 < /dev/null | FileCheck -check-prefix PPC64-ELFv2 %s
+// PPC64-ELFv1:#define _CALL_ELF 1
+// PPC64-ELFv2:#define _CALL_ELF 2
 //
 // RUN: %clang_cc1 -E -dM -ffreestanding -triple=powerpc-none-none -fno-signed-char < /dev/null | FileCheck -check-prefix PPC %s
 //