ToolChains.cpp revision 195341
1193326Sed//===--- ToolChains.cpp - ToolChain Implementations ---------------------*-===// 2193326Sed// 3193326Sed// The LLVM Compiler Infrastructure 4193326Sed// 5193326Sed// This file is distributed under the University of Illinois Open Source 6193326Sed// License. See LICENSE.TXT for details. 7193326Sed// 8193326Sed//===----------------------------------------------------------------------===// 9193326Sed 10193326Sed#include "ToolChains.h" 11193326Sed 12193326Sed#include "clang/Driver/Arg.h" 13193326Sed#include "clang/Driver/ArgList.h" 14193326Sed#include "clang/Driver/Driver.h" 15193326Sed#include "clang/Driver/DriverDiagnostic.h" 16193326Sed#include "clang/Driver/HostInfo.h" 17193326Sed#include "clang/Driver/Option.h" 18193326Sed 19193326Sed#include "llvm/ADT/StringExtras.h" 20193326Sed#include "llvm/Support/raw_ostream.h" 21193326Sed#include "llvm/System/Path.h" 22193326Sed 23193326Sed#include <cstdlib> // ::getenv 24193326Sed 25193326Sedusing namespace clang::driver; 26193326Sedusing namespace clang::driver::toolchains; 27193326Sed 28193326Sed/// Darwin_X86 - Darwin tool chain for i386 and x86_64. 29193326Sed 30193326SedDarwin_X86::Darwin_X86(const HostInfo &Host, const llvm::Triple& Triple, 31193326Sed const unsigned (&_DarwinVersion)[3], 32193326Sed const unsigned (&_GCCVersion)[3]) 33193326Sed : ToolChain(Host, Triple) { 34193326Sed DarwinVersion[0] = _DarwinVersion[0]; 35193326Sed DarwinVersion[1] = _DarwinVersion[1]; 36193326Sed DarwinVersion[2] = _DarwinVersion[2]; 37193326Sed GCCVersion[0] = _GCCVersion[0]; 38193326Sed GCCVersion[1] = _GCCVersion[1]; 39193326Sed GCCVersion[2] = _GCCVersion[2]; 40193326Sed 41193326Sed llvm::raw_string_ostream(MacosxVersionMin) 42193326Sed << "10." << DarwinVersion[0] - 4 << '.' << DarwinVersion[1]; 43193326Sed 44193326Sed ToolChainDir = "i686-apple-darwin"; 45193326Sed ToolChainDir += llvm::utostr(DarwinVersion[0]); 46193326Sed ToolChainDir += "/"; 47193326Sed ToolChainDir += llvm::utostr(GCCVersion[0]); 48193326Sed ToolChainDir += '.'; 49193326Sed ToolChainDir += llvm::utostr(GCCVersion[1]); 50193326Sed ToolChainDir += '.'; 51193326Sed ToolChainDir += llvm::utostr(GCCVersion[2]); 52193326Sed 53193326Sed std::string Path; 54193326Sed if (getArchName() == "x86_64") { 55193326Sed Path = getHost().getDriver().Dir; 56193326Sed Path += "/../lib/gcc/"; 57193326Sed Path += getToolChainDir(); 58193326Sed Path += "/x86_64"; 59193326Sed getFilePaths().push_back(Path); 60193326Sed 61193326Sed Path = "/usr/lib/gcc/"; 62193326Sed Path += getToolChainDir(); 63193326Sed Path += "/x86_64"; 64193326Sed getFilePaths().push_back(Path); 65193326Sed } 66193326Sed 67193326Sed Path = getHost().getDriver().Dir; 68193326Sed Path += "/../lib/gcc/"; 69193326Sed Path += getToolChainDir(); 70193326Sed getFilePaths().push_back(Path); 71193326Sed 72193326Sed Path = "/usr/lib/gcc/"; 73193326Sed Path += getToolChainDir(); 74193326Sed getFilePaths().push_back(Path); 75193326Sed 76193326Sed Path = getHost().getDriver().Dir; 77193326Sed Path += "/../libexec/gcc/"; 78193326Sed Path += getToolChainDir(); 79193326Sed getProgramPaths().push_back(Path); 80193326Sed 81193326Sed Path = "/usr/libexec/gcc/"; 82193326Sed Path += getToolChainDir(); 83193326Sed getProgramPaths().push_back(Path); 84193326Sed 85193326Sed Path = getHost().getDriver().Dir; 86193326Sed Path += "/../libexec"; 87193326Sed getProgramPaths().push_back(Path); 88193326Sed 89193326Sed getProgramPaths().push_back(getHost().getDriver().Dir); 90193326Sed} 91193326Sed 92193326SedDarwin_X86::~Darwin_X86() { 93193326Sed // Free tool implementations. 94193326Sed for (llvm::DenseMap<unsigned, Tool*>::iterator 95193326Sed it = Tools.begin(), ie = Tools.end(); it != ie; ++it) 96193326Sed delete it->second; 97193326Sed} 98193326Sed 99193326SedTool &Darwin_X86::SelectTool(const Compilation &C, 100193326Sed const JobAction &JA) const { 101193326Sed Action::ActionClass Key; 102193326Sed if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName())) 103193326Sed Key = Action::AnalyzeJobClass; 104193326Sed else 105193326Sed Key = JA.getKind(); 106193326Sed 107193326Sed Tool *&T = Tools[Key]; 108193326Sed if (!T) { 109193326Sed switch (Key) { 110193326Sed case Action::InputClass: 111193326Sed case Action::BindArchClass: 112193326Sed assert(0 && "Invalid tool kind."); 113193326Sed case Action::PreprocessJobClass: 114193326Sed T = new tools::darwin::Preprocess(*this); break; 115193326Sed case Action::AnalyzeJobClass: 116193326Sed T = new tools::Clang(*this); break; 117193326Sed case Action::PrecompileJobClass: 118193326Sed case Action::CompileJobClass: 119193326Sed T = new tools::darwin::Compile(*this); break; 120193326Sed case Action::AssembleJobClass: 121193326Sed T = new tools::darwin::Assemble(*this); break; 122193326Sed case Action::LinkJobClass: 123193326Sed T = new tools::darwin::Link(*this, MacosxVersionMin.c_str()); break; 124193326Sed case Action::LipoJobClass: 125193326Sed T = new tools::darwin::Lipo(*this); break; 126193326Sed } 127193326Sed } 128193326Sed 129193326Sed return *T; 130193326Sed} 131193326Sed 132193326SedDerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const { 133193326Sed DerivedArgList *DAL = new DerivedArgList(Args, false); 134193326Sed const OptTable &Opts = getHost().getDriver().getOpts(); 135193326Sed 136193326Sed // FIXME: We really want to get out of the tool chain level argument 137193326Sed // translation business, as it makes the driver functionality much 138193326Sed // more opaque. For now, we follow gcc closely solely for the 139193326Sed // purpose of easily achieving feature parity & testability. Once we 140193326Sed // have something that works, we should reevaluate each translation 141193326Sed // and try to push it down into tool specific logic. 142193326Sed 143193326Sed Arg *OSXVersion = 144193326Sed Args.getLastArg(options::OPT_mmacosx_version_min_EQ, false); 145193326Sed Arg *iPhoneVersion = 146193326Sed Args.getLastArg(options::OPT_miphoneos_version_min_EQ, false); 147193326Sed if (OSXVersion && iPhoneVersion) { 148193326Sed getHost().getDriver().Diag(clang::diag::err_drv_argument_not_allowed_with) 149193326Sed << OSXVersion->getAsString(Args) 150193326Sed << iPhoneVersion->getAsString(Args); 151193326Sed } else if (!OSXVersion && !iPhoneVersion) { 152193326Sed // Chose the default version based on the arch. 153193326Sed // 154193326Sed // FIXME: This will need to be fixed when we merge in arm support. 155193326Sed 156193326Sed // Look for MACOSX_DEPLOYMENT_TARGET, otherwise use the version 157193326Sed // from the host. 158193326Sed const char *Version = ::getenv("MACOSX_DEPLOYMENT_TARGET"); 159193326Sed if (!Version) 160193326Sed Version = MacosxVersionMin.c_str(); 161193326Sed const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); 162193326Sed DAL->append(DAL->MakeJoinedArg(0, O, Version)); 163193326Sed } 164193326Sed 165193326Sed for (ArgList::iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { 166193326Sed Arg *A = *it; 167193326Sed 168193326Sed if (A->getOption().matches(options::OPT_Xarch__)) { 169193326Sed // FIXME: Canonicalize name. 170193326Sed if (getArchName() != A->getValue(Args, 0)) 171193326Sed continue; 172193326Sed 173193326Sed // FIXME: The arg is leaked here, and we should have a nicer 174193326Sed // interface for this. 175193326Sed unsigned Prev, Index = Prev = A->getIndex() + 1; 176193326Sed Arg *XarchArg = Opts.ParseOneArg(Args, Index); 177193326Sed 178193326Sed // If the argument parsing failed or more than one argument was 179193326Sed // consumed, the -Xarch_ argument's parameter tried to consume 180193326Sed // extra arguments. Emit an error and ignore. 181193326Sed // 182193326Sed // We also want to disallow any options which would alter the 183193326Sed // driver behavior; that isn't going to work in our model. We 184193326Sed // use isDriverOption() as an approximation, although things 185193326Sed // like -O4 are going to slip through. 186193326Sed if (!XarchArg || Index > Prev + 1 || 187193326Sed XarchArg->getOption().isDriverOption()) { 188193326Sed getHost().getDriver().Diag(clang::diag::err_drv_invalid_Xarch_argument) 189193326Sed << A->getAsString(Args); 190193326Sed continue; 191193326Sed } 192193326Sed 193193326Sed XarchArg->setBaseArg(A); 194193326Sed A = XarchArg; 195193326Sed } 196193326Sed 197193326Sed // Sob. These is strictly gcc compatible for the time being. Apple 198193326Sed // gcc translates options twice, which means that self-expanding 199193326Sed // options add duplicates. 200193326Sed options::ID id = A->getOption().getId(); 201193326Sed switch (id) { 202193326Sed default: 203193326Sed DAL->append(A); 204193326Sed break; 205193326Sed 206193326Sed case options::OPT_mkernel: 207193326Sed case options::OPT_fapple_kext: 208193326Sed DAL->append(A); 209193326Sed DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_static))); 210193326Sed DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_static))); 211193326Sed break; 212193326Sed 213193326Sed case options::OPT_dependency_file: 214193326Sed DAL->append(DAL->MakeSeparateArg(A, Opts.getOption(options::OPT_MF), 215193326Sed A->getValue(Args))); 216193326Sed break; 217193326Sed 218193326Sed case options::OPT_gfull: 219193326Sed DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_g_Flag))); 220193326Sed DAL->append(DAL->MakeFlagArg(A, 221193326Sed Opts.getOption(options::OPT_fno_eliminate_unused_debug_symbols))); 222193326Sed break; 223193326Sed 224193326Sed case options::OPT_gused: 225193326Sed DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_g_Flag))); 226193326Sed DAL->append(DAL->MakeFlagArg(A, 227193326Sed Opts.getOption(options::OPT_feliminate_unused_debug_symbols))); 228193326Sed break; 229193326Sed 230193326Sed case options::OPT_fterminated_vtables: 231193326Sed case options::OPT_findirect_virtual_calls: 232193326Sed DAL->append(DAL->MakeFlagArg(A, 233193326Sed Opts.getOption(options::OPT_fapple_kext))); 234193326Sed DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_static))); 235193326Sed break; 236193326Sed 237193326Sed case options::OPT_shared: 238193326Sed DAL->append(DAL->MakeFlagArg(A, Opts.getOption(options::OPT_dynamiclib))); 239193326Sed break; 240193326Sed 241193326Sed case options::OPT_fconstant_cfstrings: 242193326Sed DAL->append(DAL->MakeFlagArg(A, 243193326Sed Opts.getOption(options::OPT_mconstant_cfstrings))); 244193326Sed break; 245193326Sed 246193326Sed case options::OPT_fno_constant_cfstrings: 247193326Sed DAL->append(DAL->MakeFlagArg(A, 248193326Sed Opts.getOption(options::OPT_mno_constant_cfstrings))); 249193326Sed break; 250193326Sed 251193326Sed case options::OPT_Wnonportable_cfstrings: 252193326Sed DAL->append(DAL->MakeFlagArg(A, 253193326Sed Opts.getOption(options::OPT_mwarn_nonportable_cfstrings))); 254193326Sed break; 255193326Sed 256193326Sed case options::OPT_Wno_nonportable_cfstrings: 257193326Sed DAL->append(DAL->MakeFlagArg(A, 258193326Sed Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings))); 259193326Sed break; 260193326Sed 261193326Sed case options::OPT_fpascal_strings: 262193326Sed DAL->append(DAL->MakeFlagArg(A, 263193326Sed Opts.getOption(options::OPT_mpascal_strings))); 264193326Sed break; 265193326Sed 266193326Sed case options::OPT_fno_pascal_strings: 267193326Sed DAL->append(DAL->MakeFlagArg(A, 268193326Sed Opts.getOption(options::OPT_mno_pascal_strings))); 269193326Sed break; 270193326Sed } 271193326Sed } 272193326Sed 273193326Sed // FIXME: Actually, gcc always adds this, but it is filtered for 274193326Sed // duplicates somewhere. This also changes the order of things, so 275193326Sed // look it up. 276193326Sed if (getArchName() == "x86_64") 277193326Sed if (!Args.hasArg(options::OPT_m64, false)) 278193326Sed DAL->append(DAL->MakeFlagArg(0, Opts.getOption(options::OPT_m64))); 279193326Sed 280193326Sed if (!Args.hasArg(options::OPT_mtune_EQ, false)) 281193326Sed DAL->append(DAL->MakeJoinedArg(0, Opts.getOption(options::OPT_mtune_EQ), 282193326Sed "core2")); 283193326Sed 284193326Sed return DAL; 285193326Sed} 286193326Sed 287193326Sedbool Darwin_X86::IsMathErrnoDefault() const { 288193326Sed return false; 289193326Sed} 290193326Sed 291193326Sedbool Darwin_X86::IsUnwindTablesDefault() const { 292193326Sed // FIXME: Gross; we should probably have some separate target 293193326Sed // definition, possibly even reusing the one in clang. 294193326Sed return getArchName() == "x86_64"; 295193326Sed} 296193326Sed 297193326Sedconst char *Darwin_X86::GetDefaultRelocationModel() const { 298193326Sed return "pic"; 299193326Sed} 300193326Sed 301193326Sedconst char *Darwin_X86::GetForcedPicModel() const { 302193326Sed if (getArchName() == "x86_64") 303193326Sed return "pic"; 304193326Sed return 0; 305193326Sed} 306193326Sed 307193326Sed/// Generic_GCC - A tool chain using the 'gcc' command to perform 308193326Sed/// all subcommands; this relies on gcc translating the majority of 309193326Sed/// command line options. 310193326Sed 311193326SedGeneric_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple) 312193326Sed : ToolChain(Host, Triple) 313193326Sed{ 314193326Sed std::string Path(getHost().getDriver().Dir); 315193326Sed Path += "/../libexec"; 316193326Sed getProgramPaths().push_back(Path); 317193326Sed 318193326Sed getProgramPaths().push_back(getHost().getDriver().Dir); 319193326Sed} 320193326Sed 321193326SedGeneric_GCC::~Generic_GCC() { 322193326Sed // Free tool implementations. 323193326Sed for (llvm::DenseMap<unsigned, Tool*>::iterator 324193326Sed it = Tools.begin(), ie = Tools.end(); it != ie; ++it) 325193326Sed delete it->second; 326193326Sed} 327193326Sed 328193326SedTool &Generic_GCC::SelectTool(const Compilation &C, 329193326Sed const JobAction &JA) const { 330193326Sed Action::ActionClass Key; 331193326Sed if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName())) 332193326Sed Key = Action::AnalyzeJobClass; 333193326Sed else 334193326Sed Key = JA.getKind(); 335193326Sed 336193326Sed Tool *&T = Tools[Key]; 337193326Sed if (!T) { 338193326Sed switch (Key) { 339193326Sed case Action::InputClass: 340193326Sed case Action::BindArchClass: 341193326Sed assert(0 && "Invalid tool kind."); 342193326Sed case Action::PreprocessJobClass: 343193326Sed T = new tools::gcc::Preprocess(*this); break; 344193326Sed case Action::PrecompileJobClass: 345193326Sed T = new tools::gcc::Precompile(*this); break; 346193326Sed case Action::AnalyzeJobClass: 347193326Sed T = new tools::Clang(*this); break; 348193326Sed case Action::CompileJobClass: 349193326Sed T = new tools::gcc::Compile(*this); break; 350193326Sed case Action::AssembleJobClass: 351193326Sed T = new tools::gcc::Assemble(*this); break; 352193326Sed case Action::LinkJobClass: 353193326Sed T = new tools::gcc::Link(*this); break; 354193326Sed 355193326Sed // This is a bit ungeneric, but the only platform using a driver 356193326Sed // driver is Darwin. 357193326Sed case Action::LipoJobClass: 358193326Sed T = new tools::darwin::Lipo(*this); break; 359193326Sed } 360193326Sed } 361193326Sed 362193326Sed return *T; 363193326Sed} 364193326Sed 365193326Sedbool Generic_GCC::IsMathErrnoDefault() const { 366193326Sed return true; 367193326Sed} 368193326Sed 369193326Sedbool Generic_GCC::IsUnwindTablesDefault() const { 370193326Sed // FIXME: Gross; we should probably have some separate target 371193326Sed // definition, possibly even reusing the one in clang. 372193326Sed return getArchName() == "x86_64"; 373193326Sed} 374193326Sed 375193326Sedconst char *Generic_GCC::GetDefaultRelocationModel() const { 376193326Sed return "static"; 377193326Sed} 378193326Sed 379193326Sedconst char *Generic_GCC::GetForcedPicModel() const { 380193326Sed return 0; 381193326Sed} 382193326Sed 383193326SedDerivedArgList *Generic_GCC::TranslateArgs(InputArgList &Args) const { 384193326Sed return new DerivedArgList(Args, true); 385193326Sed} 386193326Sed 387195341Sed/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. 388195341Sed 389195341SedOpenBSD::OpenBSD(const HostInfo &Host, const llvm::Triple& Triple) 390195341Sed : Generic_GCC(Host, Triple) { 391195341Sed getFilePaths().push_back(getHost().getDriver().Dir + "/../lib"); 392195341Sed getFilePaths().push_back("/usr/lib"); 393195341Sed} 394195341Sed 395195341SedTool &OpenBSD::SelectTool(const Compilation &C, const JobAction &JA) const { 396195341Sed Action::ActionClass Key; 397195341Sed if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName())) 398195341Sed Key = Action::AnalyzeJobClass; 399195341Sed else 400195341Sed Key = JA.getKind(); 401195341Sed 402195341Sed Tool *&T = Tools[Key]; 403195341Sed if (!T) { 404195341Sed switch (Key) { 405195341Sed case Action::AssembleJobClass: 406195341Sed T = new tools::openbsd::Assemble(*this); break; 407195341Sed case Action::LinkJobClass: 408195341Sed T = new tools::openbsd::Link(*this); break; 409195341Sed default: 410195341Sed T = &Generic_GCC::SelectTool(C, JA); 411195341Sed } 412195341Sed } 413195341Sed 414195341Sed return *T; 415195341Sed} 416195341Sed 417193326Sed/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. 418193326Sed 419193326SedFreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple, bool Lib32) 420193326Sed : Generic_GCC(Host, Triple) { 421193326Sed if (Lib32) { 422193326Sed getFilePaths().push_back(getHost().getDriver().Dir + "/../lib32"); 423193326Sed getFilePaths().push_back("/usr/lib32"); 424193326Sed } else { 425193326Sed getFilePaths().push_back(getHost().getDriver().Dir + "/../lib"); 426193326Sed getFilePaths().push_back("/usr/lib"); 427193326Sed } 428193326Sed} 429193326Sed 430193326SedTool &FreeBSD::SelectTool(const Compilation &C, const JobAction &JA) const { 431193326Sed Action::ActionClass Key; 432193326Sed if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName())) 433193326Sed Key = Action::AnalyzeJobClass; 434193326Sed else 435193326Sed Key = JA.getKind(); 436193326Sed 437193326Sed Tool *&T = Tools[Key]; 438193326Sed if (!T) { 439193326Sed switch (Key) { 440193326Sed case Action::AssembleJobClass: 441193326Sed T = new tools::freebsd::Assemble(*this); break; 442193326Sed case Action::LinkJobClass: 443193326Sed T = new tools::freebsd::Link(*this); break; 444193326Sed default: 445193326Sed T = &Generic_GCC::SelectTool(C, JA); 446193326Sed } 447193326Sed } 448193326Sed 449193326Sed return *T; 450193326Sed} 451193326Sed 452193326Sed/// Linux toolchain (very bare-bones at the moment). 453193326Sed 454193326SedLinux::Linux(const HostInfo &Host, const llvm::Triple& Triple) 455193326Sed : Generic_GCC(Host, Triple) { 456193326Sed getFilePaths().push_back(getHost().getDriver().Dir + "/../lib/clang/1.0/"); 457193326Sed getFilePaths().push_back("/lib/"); 458193326Sed getFilePaths().push_back("/usr/lib/"); 459193326Sed // FIXME: Figure out some way to get gcc's libdir 460193326Sed // (e.g. /usr/lib/gcc/i486-linux-gnu/4.3/ for Ubuntu 32-bit); we need 461193326Sed // crtbegin.o/crtend.o/etc., and want static versions of various 462193326Sed // libraries. If we had our own crtbegin.o/crtend.o/etc, we could probably 463193326Sed // get away with using shared versions in /usr/lib, though. 464193326Sed // We could fall back to the approach we used for includes (a massive 465193326Sed // list), but that's messy at best. 466193326Sed} 467193326Sed 468193326Sed/// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. 469193326Sed 470193326SedDragonFly::DragonFly(const HostInfo &Host, const llvm::Triple& Triple) 471193326Sed : Generic_GCC(Host, Triple) { 472193326Sed 473193326Sed // Path mangling to find libexec 474193326Sed std::string Path(getHost().getDriver().Dir); 475193326Sed 476193326Sed Path += "/../libexec"; 477193326Sed getProgramPaths().push_back(Path); 478193326Sed getProgramPaths().push_back(getHost().getDriver().Dir); 479193326Sed 480193326Sed getFilePaths().push_back(getHost().getDriver().Dir + "/../lib"); 481193326Sed getFilePaths().push_back("/usr/lib"); 482193326Sed getFilePaths().push_back("/usr/lib/gcc41"); 483193326Sed} 484193326Sed 485193326SedTool &DragonFly::SelectTool(const Compilation &C, const JobAction &JA) const { 486193326Sed Action::ActionClass Key; 487193326Sed if (getHost().getDriver().ShouldUseClangCompiler(C, JA, getArchName())) 488193326Sed Key = Action::AnalyzeJobClass; 489193326Sed else 490193326Sed Key = JA.getKind(); 491193326Sed 492193326Sed Tool *&T = Tools[Key]; 493193326Sed if (!T) { 494193326Sed switch (Key) { 495193326Sed case Action::AssembleJobClass: 496193326Sed T = new tools::dragonfly::Assemble(*this); break; 497193326Sed case Action::LinkJobClass: 498193326Sed T = new tools::dragonfly::Link(*this); break; 499193326Sed default: 500193326Sed T = &Generic_GCC::SelectTool(C, JA); 501193326Sed } 502193326Sed } 503193326Sed 504193326Sed return *T; 505193326Sed} 506