On 2008-01-06, at 21:31, Gordon Henriksen wrote: > Author: gordon > Date: Sun Jan 6 20:31:11 2008 > New Revision: 45676 > > URL: http://llvm.org/viewvc/llvm-project?rev=45676&view=rev > Log: > Setting GlobalDirective in TargetAsmInfo by default rather than > providing a misleading facility. It's used once in the MIPS backend > and hardcoded as "\t.globl\t" everywhere else. > > Added: > llvm/trunk/lib/CodeGen/OcamlCollector.cpp > llvm/trunk/test/CodeGen/Generic/GC/frame_size.ll > llvm/trunk/test/CodeGen/Generic/GC/simple_ocaml.ll > Modified: > llvm/trunk/include/llvm/CallingConv.h > llvm/trunk/include/llvm/CodeGen/LinkAllCodegenComponents.h
Oops. Here's the correct message for this commit: The new OcamlCollector emits the Ocaml frametable data structure and related symbols. Example output: $ llvm-as -o simple_ocaml.bc simple_ocaml.ll $ llc -gc=ocaml -asm-verbose -o - simple_ocaml.bc .text _camlSimple_ocaml__code_begin: .data _camlSimple_ocaml__data_begin: .text .align 4,0x90 .globl _fun _fun: subl $12, %esp movl $0, 4(%esp) movl $0, 8(%esp) movl 16(%esp), %eax movl %eax, 4(%esp) LBB1_1: # bb.loop movl 4(%esp), %eax movl 4(%eax), %eax testl %eax, %eax je LBB1_1 # bb.loop LBB1_2: # bb.end movl $8, (%esp) call L_malloc$stub Llabel1: movl %eax, 8(%esp) movl 4(%esp), %ecx movl %ecx, 4(%ecx) addl $12, %esp ret .section __IMPORT,__jump_table,symbol_stubs,self_modifying_code +pure_instructions,5 L_malloc$stub: .indirect_symbol _malloc hlt ; hlt ; hlt ; hlt ; hlt .subsections_via_symbols .text _camlSimple_ocaml__code_end: .data _camlSimple_ocaml__data_end: .long 0 _camlSimple_ocaml__frametable: # live roots for fun .long Llabel1 # call return address .short 0xc # stack frame size .short 0x2 # live root count .word 4 # stack offset .word 8 # stack offset .align 2 — Gordon > Modified: llvm/trunk/include/llvm/CallingConv.h > URL: > http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CallingConv.h?rev=45676&r1=45675&r2=45676&view=diff > > = > = > = > = > = > = > = > = > ====================================================================== > --- llvm/trunk/include/llvm/CallingConv.h (original) > +++ llvm/trunk/include/llvm/CallingConv.h Sun Jan 6 20:31:11 2008 > @@ -57,7 +57,12 @@ > /// X86_FastCall - 'fast' analog of X86_StdCall. Passes first > two arguments > /// in ECX:EDX registers, others - via stack. Callee is > responsible for > /// stack cleaning. > - X86_FastCall = 65 > + X86_FastCall = 65, > + > + /// X86_Ocaml - This is a weird ABI used by Objective Caml. > Formally, it > + /// supports only one to six integer/address arguments, all in- > reg. It also > + /// supports tail call emission. > + X86_Ocaml = 66 > }; > } // End CallingConv namespace > > > Modified: llvm/trunk/include/llvm/CodeGen/LinkAllCodegenComponents.h > URL: > http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/LinkAllCodegenComponents.h?rev=45676&r1=45675&r2=45676&view=diff > > = > = > = > = > = > = > = > = > ====================================================================== > --- llvm/trunk/include/llvm/CodeGen/LinkAllCodegenComponents.h > (original) > +++ llvm/trunk/include/llvm/CodeGen/LinkAllCodegenComponents.h Sun > Jan 6 20:31:11 2008 > @@ -36,6 +36,7 @@ > > (void) llvm::createSimpleRegisterCoalescer(); > > + (void) llvm::createOcamlCollector(); > (void) llvm::createShadowStackCollector(); > > (void) llvm::createBURRListDAGScheduler(NULL, NULL, NULL); > > Added: llvm/trunk/lib/CodeGen/OcamlCollector.cpp > URL: > http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/OcamlCollector.cpp?rev=45676&view=auto > > = > = > = > = > = > = > = > = > ====================================================================== > --- llvm/trunk/lib/CodeGen/OcamlCollector.cpp (added) > +++ llvm/trunk/lib/CodeGen/OcamlCollector.cpp Sun Jan 6 20:31:11 2008 > @@ -0,0 +1,177 @@ > +//===-- OcamlCollector.cpp - Ocaml frametable emitter > ---------------------===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open > Source > +// License. See LICENSE.TXT for details. > +// > +// > = > = > = > ----------------------------------------------------------------------= > ==// > +// > +// This file implements lowering for the llvm.gc* intrinsics > compatible with > +// Objective Caml 3.10.0, which uses a liveness-accurate static > stack map. > +// > +// > = > = > = > ----------------------------------------------------------------------= > ==// > + > +#include "llvm/CodeGen/Collectors.h" > +#include "llvm/ADT/DenseMap.h" > +#include "llvm/CodeGen/AsmPrinter.h" > +#include "llvm/CodeGen/Collector.h" > +#include "llvm/CodeGen/CollectorMetadata.h" > +#include "llvm/Function.h" > +#include "llvm/Module.h" > +#include "llvm/PassManager.h" > +#include "llvm/Support/Compiler.h" > +#include "llvm/Target/TargetAsmInfo.h" > +#include "llvm/Target/TargetData.h" > +#include "llvm/Target/TargetMachine.h" > +#include <ctype.h> > + > +using namespace llvm; > + > +namespace { > + > + class VISIBILITY_HIDDEN OcamlCollector : public Collector { > + public: > + OcamlCollector(); > + > + void beginAssembly(std::ostream &OS, AsmPrinter &AP, > + const TargetAsmInfo &TAI); > + > + void finishAssembly(std::ostream &OS, AsmPrinter &AP, > + const TargetAsmInfo &TAI); > + }; > + > + CollectorRegistry::Add<OcamlCollector> > + X("ocaml", "ocaml 3.10-compatible collector"); > + > +} > + > +// > ----------------------------------------------------------------------------- > + > +static void EmitCamlGlobal(const Module &M, std::ostream &OS, > AsmPrinter &AP, > + const TargetAsmInfo &TAI, const char > *Id) { > + const std::string &MId = M.getModuleIdentifier(); > + > + std::string Mangled; > + Mangled += TAI.getGlobalPrefix(); > + Mangled += "caml"; > + size_t Letter = Mangled.size(); > + Mangled.append(MId.begin(), std::find(MId.begin(), MId.end(), > '.')); > + Mangled += "__"; > + Mangled += Id; > + > + // Capitalize the first letter of the module name. > + Mangled[Letter] = toupper(Mangled[Letter]); > + > + if (const char *GlobalDirective = TAI.getGlobalDirective()) > + OS << GlobalDirective << Mangled << "\n"; > + OS << Mangled << ":\n"; > +} > + > +Collector *llvm::createOcamlCollector() { > + return new OcamlCollector(); > +} > + > +OcamlCollector::OcamlCollector() { > + NeededSafePoints = 1 << GC::PostCall; > +} > + > +void OcamlCollector::beginAssembly(std::ostream &OS, AsmPrinter &AP, > + const TargetAsmInfo &TAI) { > + AP.SwitchToTextSection(TAI.getTextSection()); > + EmitCamlGlobal(getModule(), OS, AP, TAI, "code_begin"); > + > + AP.SwitchToDataSection(TAI.getDataSection()); > + EmitCamlGlobal(getModule(), OS, AP, TAI, "data_begin"); > +} > + > +/// emitAssembly - Print the frametable. The ocaml frametable > format is thus: > +/// > +/// extern "C" struct align(sizeof(intptr_t)) { > +/// uint16_t NumDescriptors; > +/// struct align(sizeof(intptr_t)) { > +/// void *ReturnAddress; > +/// uint16_t FrameSize; > +/// uint16_t NumLiveOffsets; > +/// uint16_t LiveOffsets[NumLiveOffsets]; > +/// } Descriptors[NumDescriptors]; > +/// } caml${module}__frametable; > +/// > +/// Note that this precludes programs from stack frames larger than > 64K > +/// (FrameSize and LiveOffsets would overflow). FrameTablePrinter > will abort if > +/// either condition is detected in a function which uses the > collector. > +/// > +void OcamlCollector::finishAssembly(std::ostream &OS, AsmPrinter &AP, > + const TargetAsmInfo &TAI) { > + const char *AddressDirective; > + int AddressAlignLog; > + if (AP.TM.getTargetData()->getPointerSize() == sizeof(int32_t)) { > + AddressDirective = TAI.getData32bitsDirective(); > + AddressAlignLog = 2; > + } else { > + AddressDirective = TAI.getData64bitsDirective(); > + AddressAlignLog = 3; > + } > + > + AP.SwitchToTextSection(TAI.getTextSection()); > + EmitCamlGlobal(getModule(), OS, AP, TAI, "code_end"); > + > + AP.SwitchToDataSection(TAI.getDataSection()); > + EmitCamlGlobal(getModule(), OS, AP, TAI, "data_end"); > + > + OS << AddressDirective << 0; // FIXME: Why does ocaml emit this?? > + AP.EOL(); > + > + AP.SwitchToDataSection(TAI.getDataSection()); > + EmitCamlGlobal(getModule(), OS, AP, TAI, "frametable"); > + > + for (iterator FI = begin(), FE = end(); FI != FE; ++FI) { > + CollectorMetadata &MD = **FI; > + > + OS << "\t" << TAI.getCommentString() << " live roots for " > + << MD.getFunction().getNameStart() << "\n"; > + > + for (CollectorMetadata::iterator PI = MD.begin(), > + PE = MD.end(); PI != PE; ++PI) { > + > + uint64_t FrameSize = MD.getFrameSize(); > + if (FrameSize >= 2<<16) { > + cerr << "Function '" << MD.getFunction().getNameStart() > + << "' is too large for the ocaml collector! " > + << "Frame size " << FrameSize << " >= 65536.\n"; > + abort(); // Very rude! > + } > + > + size_t LiveCount = MD.live_size(PI); > + if (LiveCount >= 2<<16) { > + cerr << "Function '" << MD.getFunction().getNameStart() > + << "' is too large for the ocaml collector! " > + << "Live root count " << LiveCount << " >= 65536.\n"; > + abort(); // Very rude! > + } > + > + OS << AddressDirective > + << TAI.getPrivateGlobalPrefix() << "label" << PI->Num; > + AP.EOL("call return address"); > + > + AP.EmitInt16(FrameSize); > + AP.EOL("stack frame size"); > + > + AP.EmitInt16(LiveCount); > + AP.EOL("live root count"); > + > + for (CollectorMetadata::live_iterator LI = MD.live_begin(PI), > + LE = MD.live_end(PI); > + LI != LE; ++LI) { > + assert(LI->StackOffset < 2<<16 && > + "GC root stack offset is outside of fixed stack > frame and out " > + "of range for Ocaml collector!"); > + > + OS << "\t.word\t" << LI->StackOffset; > + AP.EOL("stack offset"); > + } > + > + AP.EmitAlignment(AddressAlignLog); > + } > + } > +} > > Added: llvm/trunk/test/CodeGen/Generic/GC/frame_size.ll > URL: > http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Generic/GC/frame_size.ll?rev=45676&view=auto > > = > = > = > = > = > = > = > = > ====================================================================== > --- llvm/trunk/test/CodeGen/Generic/GC/frame_size.ll (added) > +++ llvm/trunk/test/CodeGen/Generic/GC/frame_size.ll Sun Jan 6 > 20:31:11 2008 > @@ -0,0 +1,14 @@ > +; RUN: llvm-as < %s | llc -asm-verbose | grep {frame size} | grep - > v 0x0 > + > +declare void @llvm.gcroot(i8** %value, i8* %tag) > +declare void @g() gc "ocaml" > + > +define void @f(i8* %arg.0, void()* %arg.1) gc "ocaml" { > +entry: > + %gcroot.0 = alloca i8* > + call void @llvm.gcroot(i8** %gcroot.0, i8* null) > + store i8* %arg.0, i8** %gcroot.0 > + call void @g() > + call void %arg.1() > + ret void > +} > > Added: llvm/trunk/test/CodeGen/Generic/GC/simple_ocaml.ll > URL: > http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/Generic/GC/simple_ocaml.ll?rev=45676&view=auto > > = > = > = > = > = > = > = > = > ====================================================================== > --- llvm/trunk/test/CodeGen/Generic/GC/simple_ocaml.ll (added) > +++ llvm/trunk/test/CodeGen/Generic/GC/simple_ocaml.ll Sun Jan 6 > 20:31:11 2008 > @@ -0,0 +1,42 @@ > +; RUN: llvm-as < %s | llc | grep caml.*__frametable > +; RUN: llvm-as < %s | llc -march=x86 | grep {movl .0} > + > +%struct.obj = type { i8*, %struct.obj* } > + > +define %struct.obj* @fun(%struct.obj* %head) gc "ocaml" { > +entry: > + %gcroot.0 = alloca i8* > + %gcroot.1 = alloca i8* > + > + call void @llvm.gcroot(i8** %gcroot.0, i8* null) > + call void @llvm.gcroot(i8** %gcroot.1, i8* null) > + > + %local.0 = bitcast i8** %gcroot.0 to %struct.obj** > + %local.1 = bitcast i8** %gcroot.1 to %struct.obj** > + > + store %struct.obj* %head, %struct.obj** %local.0 > + br label %bb.loop > +bb.loop: > + %t0 = load %struct.obj** %local.0 > + %t1 = getelementptr %struct.obj* %t0, i32 0, i32 1 > + %t2 = bitcast %struct.obj* %t0 to i8* > + %t3 = bitcast %struct.obj** %t1 to i8** > + %t4 = call i8* @llvm.gcread(i8* %t2, i8** %t3) > + %t5 = bitcast i8* %t4 to %struct.obj* > + %t6 = icmp eq %struct.obj* %t5, null > + br i1 %t6, label %bb.loop, label %bb.end > +bb.end: > + %t7 = malloc %struct.obj > + store %struct.obj* %t7, %struct.obj** %local.1 > + %t8 = bitcast %struct.obj* %t7 to i8* > + %t9 = load %struct.obj** %local.0 > + %t10 = getelementptr %struct.obj* %t9, i32 0, i32 1 > + %t11 = bitcast %struct.obj* %t9 to i8* > + %t12 = bitcast %struct.obj** %t10 to i8** > + call void @llvm.gcwrite(i8* %t8, i8* %t11, i8** %t12) > + ret %struct.obj* %t7 > +} > + > +declare void @llvm.gcroot(i8** %value, i8* %tag) > +declare void @llvm.gcwrite(i8* %value, i8* %obj, i8** %field) > +declare i8* @llvm.gcread(i8* %obj, i8** %field) _______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits