Skip to content

Commit 22db8b1

Browse files
committed
rustc: Use memmove instructions more aggressively in DPS mode. LLVM converts these to optimized block transfer instructions, significantly reducing code size.
1 parent 4b7884e commit 22db8b1

File tree

1 file changed

+74
-13
lines changed

1 file changed

+74
-13
lines changed

src/comp/middle/trans_dps.rs

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import std::ivec;
2020
import std::option::none;
2121
import std::option::some;
2222
import std::str;
23+
import std::uint;
2324

2425
import LLFalse = lib::llvm::False;
2526
import LLTrue = lib::llvm::True;
@@ -36,6 +37,30 @@ fn llelement_type(TypeRef llty) -> TypeRef {
3637
lib::llvm::llvm::LLVMGetElementType(llty)
3738
}
3839

40+
fn llalign_of(&@crate_ctxt ccx, TypeRef llty) -> uint {
41+
ret llvm::LLVMPreferredAlignmentOfType(ccx.td.lltd, llty);
42+
}
43+
44+
fn llsize_of(&@crate_ctxt ccx, TypeRef llty) -> uint {
45+
ret llvm::LLVMStoreSizeOfType(ccx.td.lltd, llty);
46+
}
47+
48+
fn mk_const(&@crate_ctxt ccx, &str name, bool exported, ValueRef llval)
49+
-> ValueRef {
50+
auto llglobal = llvm::LLVMAddGlobal(ccx.llmod, trans::val_ty(llval),
51+
str::buf(name));
52+
53+
llvm::LLVMSetInitializer(llglobal, llval);
54+
llvm::LLVMSetGlobalConstant(llglobal, LLTrue);
55+
56+
if !exported {
57+
llvm::LLVMSetLinkage(llglobal,
58+
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
59+
}
60+
61+
ret llglobal;
62+
}
63+
3964

4065
// Destination utilities
4166

@@ -138,10 +163,38 @@ fn store(&@block_ctxt bcx, &dest dest, ValueRef llsrc, bool cast)
138163
ret bcx;
139164
}
140165

141-
tag heap { hp_task; hp_shared; }
166+
fn memmove(&@block_ctxt bcx, &dest dest, ValueRef llsrcptr) -> @block_ctxt {
167+
alt (dest.slot) {
168+
// TODO: We might want to support these; I can't think of any case in
169+
// which we would want them off the top of my head, but feel free to add
170+
// them if they aid orthogonality.
171+
dst_nil { fail "dst_nil in memmove"; }
172+
dst_imm(_) { fail "dst_imm in memmove"; }
173+
dst_ptr(?lldestptr) {
174+
auto lldestty = llelement_type(trans::val_ty(llsrcptr));
175+
auto llsrcty = llelement_type(trans::val_ty(llsrcptr));
176+
auto dest_align = llalign_of(bcx_ccx(bcx), lldestty);
177+
auto src_align = llalign_of(bcx_ccx(bcx), llsrcty);
178+
auto align = uint::min(dest_align, src_align);
179+
auto llfn = bcx_ccx(bcx).intrinsics.get("llvm.memmove.p0i8.p0i8.i32");
180+
auto lldestptr_i8 = bcx.build.PointerCast(lldestptr,
181+
tc::T_ptr(tc::T_i8()));
182+
auto llsrcptr_i8 = bcx.build.PointerCast(llsrcptr,
183+
tc::T_ptr(tc::T_i8()));
184+
bcx.build.Call(llfn,
185+
~[lldestptr_i8,
186+
llsrcptr_i8,
187+
tc::C_uint(llsize_of(bcx_ccx(bcx), llsrcty)),
188+
tc::C_uint(align),
189+
tc::C_bool(false)]);
190+
ret bcx;
191+
}
192+
}
193+
}
142194

143195
// Allocates a value of the given LLVM size on either the task heap or the
144196
// shared heap.
197+
tag heap { hp_task; hp_shared; }
145198
fn malloc(&@block_ctxt bcx, ValueRef lldest, heap heap,
146199
option[ValueRef] llcustom_size_opt) -> @block_ctxt {
147200
auto llptrty = llelement_type(lltype_of(lldest));
@@ -177,7 +230,7 @@ fn trans_lit(&@block_ctxt cx, &dest dest, &ast::lit lit) -> @block_ctxt {
177230
ast::lit_str(?s, ast::sk_unique) {
178231
auto r = trans_lit_str_common(bcx_ccx(bcx), s);
179232
auto llstackpart = r._0; auto llheappartopt = r._1;
180-
bcx = store(bcx, dest, llstackpart, true);
233+
bcx = memmove(bcx, dest, llstackpart);
181234
alt (llheappartopt) {
182235
none { /* no-op */ }
183236
some(?llheappart) {
@@ -191,7 +244,8 @@ fn trans_lit(&@block_ctxt cx, &dest dest, &ast::lit lit) -> @block_ctxt {
191244
tc::T_ptr(tc::T_ptr(llheappartty)));
192245
malloc(bcx, lldestptrptr, hp_shared, none);
193246
auto lldestptr = bcx.build.Load(lldestptrptr);
194-
bcx.build.Store(llheappart, lldestptr);
247+
memmove(bcx, rec(slot=dst_ptr(lldestptr), mode=dm_copy),
248+
llheappart);
195249
}
196250
}
197251
}
@@ -341,6 +395,8 @@ fn trans_block(&@block_ctxt cx, &dest dest, &ast::block block)
341395
// since that doesn't work for crate constants.
342396
fn trans_lit_str_common(&@crate_ctxt ccx, &str s)
343397
-> tup(ValueRef, option[ValueRef]) {
398+
auto llstackpart; auto llheappartopt;
399+
344400
auto len = str::byte_len(s);
345401

346402
auto array = ~[];
@@ -352,18 +408,23 @@ fn trans_lit_str_common(&@crate_ctxt ccx, &str s)
352408
array += ~[tc::C_u8(0u)];
353409
}
354410

355-
ret tup(tc::C_struct(~[tc::C_uint(len + 1u),
356-
tc::C_uint(abi::ivec_default_length),
357-
tc::C_array(tc::T_i8(), array)]),
358-
none);
359-
}
360-
361-
auto llheappart = tc::C_struct(~[tc::C_uint(len),
411+
llstackpart = tc::C_struct(~[tc::C_uint(len + 1u),
412+
tc::C_uint(abi::ivec_default_length),
362413
tc::C_array(tc::T_i8(), array)]);
363-
ret tup(tc::C_struct(~[tc::C_uint(0u),
414+
llheappartopt = none;
415+
} else {
416+
auto llheappart = tc::C_struct(~[tc::C_uint(len),
417+
tc::C_array(tc::T_i8(), array)]);
418+
llstackpart =
419+
tc::C_struct(~[tc::C_uint(0u),
364420
tc::C_uint(abi::ivec_default_length),
365-
tc::C_null(tc::T_ptr(lltype_of(llheappart)))]),
366-
some(llheappart));
421+
tc::C_null(tc::T_ptr(lltype_of(llheappart)))]);
422+
llheappartopt = some(mk_const(ccx, "const_istr_heap", false,
423+
llheappart));
424+
}
425+
426+
ret tup(mk_const(ccx, "const_istr_stack", false, llstackpart),
427+
llheappartopt);
367428
}
368429

369430
// As above, we don't use destination-passing style here.

0 commit comments

Comments
 (0)