[llvm-commits] [llvm] r45676 - in /llvm/trunk: include/llvm/CallingConv.h include/llvm/CodeGen/LinkAllCodegenComponents.h lib/CodeGen/OcamlCollector.cpp test/CodeGen/Generic/GC/frame_size.ll test/CodeGen/Generic/GC/simple_ocaml.ll
Gordon Henriksen
gordonhenriksen at mac.com
Mon Jan 7 05:21:35 PST 2008
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)
More information about the llvm-commits
mailing list