Skip to content

Commit 33fdd18

Browse files
author
Eddy Westbrook
authored
Heapster string literals (#1456)
* fixed the IRT description generation to match the recent change that made the translation of bitvector permissions to just be bitvectors * updated xor_swap_rust example to use the Rust type in the SAW script * added a case to the Rust to Heapster translator to handle function types with no return value * whoops, forgot to update the bitcode file for xor_swap_rust * bugfix in the Rust to Heapster translator: empty return types need to be converted to unit, not to the empty struct * tweaked the error message for when Rust types do not translate correctly to the expected LLVM type * started adding support for string literals by moving all creation of a HeapsterEnv into a single function which iterates through the globals and adds those it can handle * added a formatting example in Rust, and started defining the necessary types for it * started trying to figure out how Rust stores string literals in its generated LLVM files * fixed the prtty-printing for constant values * changed TrueEnum::fmt to use the fmt method rather than the write! macro * whoops, changed the fmt method for TrueEnum back to using the write! macro, because that seems to be the proper way to do things * whoops, forgot to add the repr(u64) pragma to the TrueEnum type * added a type-checking command for TrueEnum::fmt * moved some OpenTerm operators from SAWTranslation.hs to OpenTerm.hs * added llvmReadBlockOfShape * more work trying to translate globals * got string literals translated, but now there is some translation bug... * whoops, translating a shape always yields exactly one term * added helper function exprLLVMTypeBytes * added support for Rust slice types * whoops, combined the two cases for translating shared vs mutable references into one * updated funPerm3FromArgLayout to handle layouts with existential permissions * updated the rust_data example to use string literals * moved the LLVM globals code to a new file LLVMGlobalConst.hs * fixed the translation of LLVM array constants to generate SAW core BVVecs instead of SAW core Vecs * regenerated Coq files for saw-core-coq * added support for the Crucible BVZext and BVTrunc instructions, and fixed up that for BVSext * added heapster_init_env_debug and heapster_init_env_from_file_debug commands * small tweaks to rust_data.saw to get it to work * added another formatting example that we cannot handle yet...
1 parent 58ca144 commit 33fdd18

File tree

15 files changed

+567
-84
lines changed

15 files changed

+567
-84
lines changed

heapster-saw/examples/rust_data.bc

3.3 KB
Binary file not shown.

heapster-saw/examples/rust_data.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use std::collections::{HashMap, HashSet};
2+
use std::fmt;
3+
24

35
/* The logical and operation as a function on bool */
46
pub fn bool_and (x:bool, y:bool) -> bool {
@@ -229,8 +231,15 @@ impl MixedStruct {
229231
}
230232
}
231233

234+
impl fmt::Display for MixedStruct {
235+
fn fmt<'a, 'b>(&'a self, f: &'b mut fmt::Formatter) -> fmt::Result {
236+
write!(f, "s = {}, i1 = {}, i2 = {}", self.s, self.i1, self.i2)
237+
}
238+
}
239+
232240
/* A 'true' enum */
233241
#[derive(Clone, Debug, PartialEq)]
242+
#[repr(u64)]
234243
pub enum TrueEnum {
235244
Foo,
236245
Bar,
@@ -245,6 +254,22 @@ pub fn cycle_true_enum (te: &TrueEnum) -> TrueEnum {
245254
}
246255
}
247256

257+
impl fmt::Display for TrueEnum {
258+
fn fmt<'a, 'b>(&'a self, f: &'b mut fmt::Formatter) -> fmt::Result {
259+
match self {
260+
TrueEnum::Foo => f.write_str ("Foo"),
261+
TrueEnum::Bar => f.write_str ("Bar"),
262+
TrueEnum::Baz => f.write_str ("Baz"),
263+
/*
264+
TrueEnum::Foo => write!(f,"Foo"),
265+
TrueEnum::Bar => write!(f,"Bar"),
266+
TrueEnum::Baz => write!(f,"Baz"),
267+
*/
268+
}
269+
}
270+
}
271+
272+
248273
/* A linked list */
249274
#[derive(Clone, Debug, PartialEq)]
250275
#[repr(C,u64)]
@@ -295,7 +320,6 @@ pub fn list64_is_empty (l: &List64) -> bool {
295320
}
296321
}
297322

298-
299323
/* Insert a mapping into m from the greatest of x and y to the other */
300324
pub fn hash_map_insert_gt_to_le (m: &mut HashMap<u64,u64>, x:u64, y:u64) -> () {
301325
if x > y {

heapster-saw/examples/rust_data.saw

+56-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ heapster_define_perm env "int1" " " "llvmptr 1" "exists x:bv 1.eq(llvmword(x))";
1313

1414
heapster_define_llvmshape env "u64" 64 "" "fieldsh(int64<>)";
1515
heapster_define_llvmshape env "u32" 64 "" "fieldsh(32,int32<>)";
16+
heapster_define_llvmshape env "u8" 64 "" "fieldsh(8,int8<>)";
1617

1718
// bool type
1819
heapster_define_llvmshape env "bool" 64 "" "fieldsh(1,int1<>)";
@@ -29,17 +30,49 @@ heapster_define_rust_type env "pub enum Sum<X,Y> { Left (X), Right (Y) }";
2930
// The Option type
3031
heapster_define_rust_type env "pub enum Option<X> { None, Some (X) }";
3132

33+
// The str type
34+
// For now we have to define the shape explicitly without the int8 name because
35+
// we don't yet have implications on array cells
36+
//heapster_define_llvmshape env "str" 64 "" "exsh len:bv 64.arraysh(len,1,[(8,int8<>)])";
37+
heapster_define_llvmshape env "str" 64 "" "exsh len:bv 64.arraysh(len,1,[(8,exists x:bv 8.eq(llvmword(x)))])";
38+
//heapster_define_rust_type env "type str = [u8];";
39+
40+
// The String type
41+
heapster_define_llvmshape env "String" 64 "" "exsh cap:bv 64. ptrsh(arraysh(cap,1,[(8,int8<>)]));fieldsh(int64<>);fieldsh(eq(llvmword(cap)))";
42+
3243
// List type
3344
//heapster_define_llvmshape env "List" 64 "L:perm(llvmptr 64),X:llvmshape 64" "(fieldsh(eq(llvmword(0)))) orsh (fieldsh(eq(llvmword(1)));X;fieldsh(L))";
3445
//heapster_define_recursive_perm env "ListPerm" "X:llvmshape 64, Xlen:bv 64, rw:rwmodality, l:lifetime" "llvmptr 64" ["[l]memblock(rw,0,Xlen + 16,List<ListPerm<X,Xlen,rw,l>,X>)"] "\\ (X:sort 0) (_:Vec 64 Bool) -> List X" "\\ (X:sort 0) (_:Vec 64 Bool) -> foldListPermH X" "\\ (X:sort 0) (_:Vec 64 Bool) -> unfoldListPermH X";
3546
heapster_define_rust_type env "pub enum List<X> { Nil, Cons (X,Box<List<X>>) }";
3647

48+
// Void type; note that Heapster does not (yet?) support empty types, so instead
49+
// we make this type opaque. Also, note that the ArgumentV1 structure contains
50+
// referens to Void, so presumably they are just casts of other types...?
51+
//
52+
//heapster_define_rust_type env "pub enum Void {}";
53+
heapster_define_opaque_llvmshape env "Void" 64 "" "64" "#()";
54+
55+
// fmt::Error type
56+
heapster_define_rust_type_qual env "fmt" "pub struct Error { }";
57+
58+
// fmt::Result type
59+
// FIXME: there seems to be some optimization in Rust that lays out fmt::Result as a 1-bit value
60+
heapster_define_llvmshape env "fmt::Result" 64 "" "fieldsh(1,eq(llvmword(0))) orsh fieldsh(1,eq(llvmword(1)))";
61+
//heapster_define_rust_type_qual env "fmt" "pub enum Result { Ok (), Err (fmt::Error) }";
62+
63+
// fmt::Formatter type
64+
heapster_define_opaque_llvmshape env "fmt::Formatter" 64 "" "64" "#()";
65+
66+
// fmt::ArgumentV1 type
67+
//heapster_define_rust_type_qual env "fmt" "pub struct ArgumentV1<'a> { value: &'a Void, formatter: for <'b> fn(&'b Void, &'b mut fmt::Formatter) -> fmt::Result, }";
68+
69+
// fmt::Arguments type
70+
//heapster_define_rust_type_qual env "fmt" "pub struct Arguments<'a> { pieces: &'a [&'a str], fmt: Option<&'a [fmt::Argument]>, args: &'a [fmt::ArgumentV1<'a>], }";
71+
72+
3773
// List64 type
3874
heapster_define_rust_type env "pub enum List64 { Nil64, Cons64 (u64,Box<List64>) }";
3975

40-
// The String type
41-
heapster_define_llvmshape env "String" 64 "" "exsh cap:bv 64. ptrsh(arraysh(cap,1,[(8,int8<>)]));fieldsh(int64<>);fieldsh(eq(llvmword(cap)))";
42-
4376
// The TwoValues, ThreeValues, FourValues, and FiveValues types
4477
heapster_define_rust_type env "pub struct TwoValues(u32,u32);";
4578
heapster_define_rust_type env "pub struct ThreeValues(u32,u32,u32);";
@@ -104,7 +137,23 @@ heapster_assume_fun_rename env to_string_str "to_string_str" "(len:bv 64). arg0:
104137
// HashMap::insert
105138
// FIXME: we currently pretend this always returns None
106139
hashmap_u64_u64_insert_sym <- heapster_find_symbol env "std11collections4hash3map24HashMap$LT$K$C$V$C$S$GT$6insert";
107-
heapster_assume_fun_rename env hashmap_u64_u64_insert_sym "hashmap_u64_u64_insert" "<'a> fn (&'a mut HashMap<u64,u64>,u64,u64) -> Option<u64>" "\\ (endl:HashMap (Vec 64 Bool) (Vec 64 Bool) * #() -> CompM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #())) (h:HashMap (Vec 64 Bool) (Vec 64 Bool)) (k:Vec 64 Bool) (v:Vec 64 Bool) -> returnM ((#() -> CompM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #())) * Either #() (Vec 64 Bool) * #()) ((\\ (_:#()) -> returnM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #()) (Cons (Vec 64 Bool * Vec 64 Bool) (k,v) h, ())), Left #() (Vec 64 Bool) (), ())";
140+
heapster_assume_fun_rename_prim env hashmap_u64_u64_insert_sym "hashmap_u64_u64_insert" "<'a> fn (&'a mut HashMap<u64,u64>,u64,u64) -> Option<u64>";
141+
//heapster_assume_fun_rename env hashmap_u64_u64_insert_sym "hashmap_u64_u64_insert" "<'a> fn (&'a mut HashMap<u64,u64>,u64,u64) -> Option<u64>" "\\ (endl:HashMap (Vec 64 Bool) (Vec 64 Bool) * #() -> CompM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #())) (h:HashMap (Vec 64 Bool) (Vec 64 Bool)) (k:Vec 64 Bool) (v:Vec 64 Bool) -> returnM ((#() -> CompM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #())) * Either #() (Vec 64 Bool) * #()) ((\\ (_:#()) -> returnM (HashMap (Vec 64 Bool) (Vec 64 Bool) * #()) (Cons (Vec 64 Bool * Vec 64 Bool) (k,v) h, ())), Left #() (Vec 64 Bool) (), ())";
142+
143+
/*
144+
String__fmt_sym <- heapster_find_trait_method_symbol env "core::fmt::Display::fmt<String>";
145+
// heapster_assume_fun_rename env String__fmt_sym "String__fmt" "<'a, 'b> fn(&'a String, f: &'b mut fmt::Formatter) -> fmt::Result" "\\ (end_a : List (Vec 8 Bool) * #() -> CompM (List (Vec 8 Bool) * #())) (end_b : #() * #() -> CompM (#() * #())) (str:List (Vec 8 Bool)) (fmt : #()) -> returnM ((#() -> CompM (List (Vec 8 Bool) * #())) * (#() -> CompM (#() * #())) * Either #() #() * #()) ((\\ (_:#()) -> returnM (List (Vec 8 Bool) * #()) (str, ())), (\\ (_:#()) -> returnM (#() * #()) ((), ())), Left #() #() (), ())";
146+
heapster_assume_fun_rename_prim env String__fmt_sym "String__fmt" "<'a, 'b> fn(&'a String, f: &'b mut fmt::Formatter) -> fmt::Result";
147+
*/
148+
149+
150+
// Arguments::new_v1
151+
Arguments__new_v1_sym <- heapster_find_symbol env "3fmt9Arguments6new_v1";
152+
//heapster_assume_fun_rename_prim env Arguments__new_v1_sym "Arguments__new" "<'a> fn (pieces: &'a [&'a str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a>";
153+
154+
// Formatter::write_str
155+
Formatter__write_str_sym <- heapster_find_symbol env "9Formatter9write_str";
156+
heapster_assume_fun_rename_prim env Formatter__write_str_sym "Formatter__write_str" "<'a,'b> fn (&'a mut fmt::Formatter, &'b str) -> fmt::Result";
108157

109158

110159
/***
@@ -148,6 +197,9 @@ cycle_true_enum_sym <- heapster_find_symbol env "15cycle_true_enum";
148197
// NOTE: This typecheck requires full(er) support for disjunctive shapes, which Heapster currently lacks
149198
// heapster_typecheck_fun_rename env cycle_true_enum_sym "cycle_true_enum" "<'a> fn (te:&'a TrueEnum) -> TrueEnum";
150199

200+
TrueEnum__fmt_sym <- heapster_find_trait_method_symbol env "core::fmt::Display::fmt<TrueEnum>";
201+
heapster_typecheck_fun_rename env TrueEnum__fmt_sym "TrueEnum__fmt" "<'a, 'b> fn (&'a TrueEnum, f: &'b mut fmt::Formatter) -> fmt::Result";
202+
151203
// list_is_empty
152204
list_is_empty_sym <- heapster_find_symbol env "13list_is_empty";
153205
heapster_typecheck_fun_rename env list_is_empty_sym "list_is_empty" "<'a> fn (l: &'a List<u64>) -> bool";

heapster-saw/heapster-saw.cabal

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ library
2828
reflection,
2929
-- ansi-wl-pprint,
3030
prettyprinter >= 1.7.0,
31+
pretty,
3132
transformers,
3233
mtl,
3334
containers,
@@ -47,6 +48,7 @@ library
4748
Verifier.SAW.Heapster.Implication
4849
Verifier.SAW.Heapster.IRTTranslation
4950
Verifier.SAW.Heapster.Lexer
51+
Verifier.SAW.Heapster.LLVMGlobalConst
5052
Verifier.SAW.Heapster.Located
5153
Verifier.SAW.Heapster.ParsedCtx
5254
Verifier.SAW.Heapster.Parser
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
{-# LANGUAGE GADTs #-}
2+
{-# LANGUAGE ScopedTypeVariables #-}
3+
{-# LANGUAGE TypeApplications #-}
4+
{-# LANGUAGE OverloadedStrings #-}
5+
{-# LANGUAGE TypeOperators #-}
6+
{-# LANGUAGE DataKinds #-}
7+
{-# LANGUAGE ViewPatterns #-}
8+
9+
module Verifier.SAW.Heapster.LLVMGlobalConst (
10+
permEnvAddGlobalConst
11+
) where
12+
13+
import Data.Bits
14+
import Data.List
15+
import Control.Monad.Reader
16+
import GHC.TypeLits
17+
import qualified Text.PrettyPrint.HughesPJ as PPHPJ
18+
19+
import qualified Text.LLVM.AST as L
20+
import qualified Text.LLVM.PP as L
21+
22+
import Data.Binding.Hobbits hiding (sym)
23+
24+
import Data.Parameterized.NatRepr
25+
import Data.Parameterized.Some
26+
27+
import Lang.Crucible.Types
28+
import Lang.Crucible.LLVM.MemModel
29+
import Verifier.SAW.OpenTerm
30+
import Verifier.SAW.Heapster.Permissions
31+
32+
-- | Generate a SAW core term for a bitvector literal whose length is given by
33+
-- the first integer and whose value is given by the second
34+
bvLitOfIntOpenTerm :: Integer -> Integer -> OpenTerm
35+
bvLitOfIntOpenTerm n i =
36+
bvLitOpenTerm (map (testBit i) $ reverse [0..(fromIntegral n)-1])
37+
38+
-- | Helper function to build a SAW core term of type @BVVec w len a@, i.e., a
39+
-- bitvector-indexed vector, containing a given list of elements of type
40+
-- @a@. The roundabout way we do this currently requires a default element of
41+
-- type @a@, even though this value is never actually used. Also required is the
42+
-- bitvector width @w@.
43+
bvVecValueOpenTerm :: NatRepr w -> OpenTerm -> [OpenTerm] -> OpenTerm ->
44+
OpenTerm
45+
bvVecValueOpenTerm w tp ts def_tm =
46+
applyOpenTermMulti (globalOpenTerm "Prelude.genBVVecFromVec")
47+
[natOpenTerm (fromIntegral $ length ts), tp, arrayValueOpenTerm tp ts,
48+
def_tm, natOpenTerm (natValue w),
49+
bvLitOfIntOpenTerm (intValue w) (fromIntegral $ length ts)]
50+
51+
-- | The monad for translating LLVM globals to Heapster
52+
type LLVMTransM = ReaderT (PermEnv, DebugLevel) Maybe
53+
54+
-- | Run the 'LLVMTransM' monad
55+
runLLVMTransM :: LLVMTransM a -> (PermEnv, DebugLevel) -> Maybe a
56+
runLLVMTransM = runReaderT
57+
58+
-- | Use 'debugTrace' to output a string message and then call 'mzero'
59+
traceAndZeroM :: String -> LLVMTransM a
60+
traceAndZeroM msg =
61+
do (_,dlevel) <- ask
62+
debugTrace dlevel msg mzero
63+
64+
-- | Helper function to pretty-print the value of a global
65+
ppLLVMValue :: L.Value -> String
66+
ppLLVMValue val =
67+
L.withConfig (L.Config True True True) (show $ PPHPJ.nest 2 $ L.ppValue val)
68+
69+
-- | Helper function to pretty-print an LLVM constant expression
70+
ppLLVMConstExpr :: L.ConstExpr -> String
71+
ppLLVMConstExpr ce =
72+
L.withConfig (L.Config True True True) (show $ PPHPJ.nest 2 $ L.ppConstExpr ce)
73+
74+
-- | Translate a typed LLVM 'L.Value' to a Heapster permission + translation
75+
translateLLVMValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Type -> L.Value ->
76+
LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm)
77+
translateLLVMValue w tp@(L.PrimType (L.Integer n)) (L.ValInteger i) =
78+
translateLLVMType w tp >>= \(sh,_) ->
79+
return (sh, bvLitOfIntOpenTerm (fromIntegral n) i)
80+
translateLLVMValue w _ (L.ValSymbol sym) =
81+
do (env,_) <- ask
82+
-- (p, ts) <- lift (lookupGlobalSymbol env (GlobalSymbol sym) w)
83+
(p, t) <- case (lookupGlobalSymbol env (GlobalSymbol sym) w) of
84+
Just (p,[t]) -> return (p,t)
85+
Just (p,ts) -> return (p,tupleOpenTerm ts)
86+
Nothing -> traceAndZeroM ("Could not find symbol: " ++ show sym)
87+
return (PExpr_FieldShape (LLVMFieldShape p), t)
88+
translateLLVMValue w _ (L.ValArray tp elems) =
89+
do
90+
-- First, translate the elements
91+
ts <- map snd <$> mapM (translateLLVMValue w tp) elems
92+
93+
-- Array shapes can only handle field shapes elements, so translate the
94+
-- element type to and ensure it returns a field shape; FIXME: this could
95+
-- actually handle sequences of field shapes if necessary
96+
(sh, saw_tp) <- translateLLVMType w tp
97+
fsh <- case sh of
98+
PExpr_FieldShape fsh -> return fsh
99+
_ -> mzero
100+
101+
-- Compute the array stride as the length of the element shape
102+
sh_len_expr <- lift $ llvmShapeLength sh
103+
sh_len <- fromInteger <$> lift (bvMatchConstInt sh_len_expr)
104+
105+
-- Generate a default element of type tp using the zero initializer; this is
106+
-- currently needed by bvVecValueOpenTerm
107+
def_v <- llvmZeroInitValue tp
108+
(_,def_tm) <- translateLLVMValue w tp def_v
109+
110+
-- Finally, build our array shape and SAW core value
111+
return (PExpr_ArrayShape (bvInt $ fromIntegral $ length elems) sh_len [fsh],
112+
bvVecValueOpenTerm w saw_tp ts def_tm)
113+
translateLLVMValue w _ (L.ValPackedStruct elems) =
114+
mapM (translateLLVMTypedValue w) elems >>= \(unzip -> (shs,ts)) ->
115+
return (foldr PExpr_SeqShape PExpr_EmptyShape shs, tupleOpenTerm ts)
116+
translateLLVMValue w tp (L.ValString bytes) =
117+
translateLLVMValue w tp (L.ValArray
118+
(L.PrimType (L.Integer 8))
119+
(map (L.ValInteger . toInteger) bytes))
120+
{-
121+
return (PExpr_ArrayShape (bvInt $ fromIntegral $ length bytes) 1
122+
[LLVMFieldShape (ValPerm_Exists $ nu $ \(bv :: Name (BVType 8)) ->
123+
ValPerm_Eq $ PExpr_LLVMWord $ PExpr_Var bv)],
124+
[arrayValueOpenTerm (bvTypeOpenTerm (8::Int)) $
125+
map (\b -> bvLitOpenTerm $ map (testBit b) [7,6..0]) bytes])
126+
-}
127+
translateLLVMValue w _ (L.ValConstExpr ce) =
128+
translateLLVMConstExpr w ce
129+
translateLLVMValue w tp L.ValZeroInit =
130+
llvmZeroInitValue tp >>= translateLLVMValue w tp
131+
translateLLVMValue _ _ v =
132+
traceAndZeroM ("translateLLVMValue does not yet handle:\n" ++ ppLLVMValue v)
133+
134+
-- | Helper function for 'translateLLVMValue'
135+
translateLLVMTypedValue :: (1 <= w, KnownNat w) => NatRepr w -> L.Typed L.Value ->
136+
LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm)
137+
translateLLVMTypedValue w (L.Typed tp v) = translateLLVMValue w tp v
138+
139+
-- | Translate an LLVM type into a shape plus the SAW core type of elements of
140+
-- the translation of that shape
141+
translateLLVMType :: (1 <= w, KnownNat w) => NatRepr w -> L.Type ->
142+
LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm)
143+
translateLLVMType _ (L.PrimType (L.Integer n))
144+
| Just (Some (n_repr :: NatRepr n)) <- someNat n
145+
, Left leq_pf <- decideLeq (knownNat @1) n_repr =
146+
withKnownNat n_repr $ withLeqProof leq_pf $
147+
return (PExpr_FieldShape (LLVMFieldShape $ ValPerm_Exists $ nu $ \bv ->
148+
ValPerm_Eq $ PExpr_LLVMWord $
149+
PExpr_Var (bv :: Name (BVType n))),
150+
(bvTypeOpenTerm n))
151+
translateLLVMType _ tp =
152+
traceAndZeroM ("translateLLVMType does not yet handle:\n"
153+
++ show (L.ppType tp))
154+
155+
-- | Helper function for 'translateLLVMValue' applied to a constant expression
156+
translateLLVMConstExpr :: (1 <= w, KnownNat w) => NatRepr w -> L.ConstExpr ->
157+
LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm)
158+
translateLLVMConstExpr w (L.ConstGEP _ _ _ (L.Typed tp ptr : ixs)) =
159+
translateLLVMValue w tp ptr >>= \ptr_trans ->
160+
translateLLVMGEP w tp ptr_trans ixs
161+
translateLLVMConstExpr w (L.ConstConv L.BitCast
162+
(L.Typed tp@(L.PtrTo _) v) (L.PtrTo _)) =
163+
-- A bitcast from one LLVM pointer type to another is a no-op for us
164+
translateLLVMValue w tp v
165+
translateLLVMConstExpr _ ce =
166+
traceAndZeroM ("translateLLVMConstExpr does not yet handle:\n"
167+
++ ppLLVMConstExpr ce)
168+
169+
-- | Helper function for 'translateLLVMValue' applied to a @getelemptr@
170+
-- expression
171+
translateLLVMGEP :: (1 <= w, KnownNat w) => NatRepr w -> L.Type ->
172+
(PermExpr (LLVMShapeType w), OpenTerm) ->
173+
[L.Typed L.Value] ->
174+
LLVMTransM (PermExpr (LLVMShapeType w), OpenTerm)
175+
translateLLVMGEP _ _ vtrans [] = return vtrans
176+
translateLLVMGEP w (L.Array _ tp) vtrans (L.Typed _ (L.ValInteger 0) : ixs) =
177+
translateLLVMGEP w tp vtrans ixs
178+
translateLLVMGEP w (L.PtrTo tp) vtrans (L.Typed _ (L.ValInteger 0) : ixs) =
179+
translateLLVMGEP w tp vtrans ixs
180+
translateLLVMGEP w (L.PackedStruct [tp]) vtrans (L.Typed
181+
_ (L.ValInteger 0) : ixs) =
182+
translateLLVMGEP w tp vtrans ixs
183+
translateLLVMGEP _ tp _ ixs =
184+
traceAndZeroM ("translateLLVMGEP cannot handle arguments:\n" ++
185+
" " ++ intercalate "," (show tp : map show ixs))
186+
187+
-- | Build an LLVM value for a @zeroinitializer@ field of the supplied type
188+
llvmZeroInitValue :: L.Type -> LLVMTransM (L.Value)
189+
llvmZeroInitValue (L.PrimType (L.Integer _)) = return $ L.ValInteger 0
190+
llvmZeroInitValue (L.Array len tp) =
191+
L.ValArray tp <$> replicate (fromIntegral len) <$> llvmZeroInitValue tp
192+
llvmZeroInitValue (L.PackedStruct tps) =
193+
L.ValPackedStruct <$> zipWith L.Typed tps <$> mapM llvmZeroInitValue tps
194+
llvmZeroInitValue tp =
195+
traceAndZeroM ("llvmZeroInitValue cannot handle type:\n"
196+
++ show (L.ppType tp))
197+
198+
-- | Add an LLVM global constant to a 'PermEnv', if the global has a type and
199+
-- value we can translate to Heapster, otherwise silently ignore it
200+
permEnvAddGlobalConst :: (1 <= w, KnownNat w) => DebugLevel -> NatRepr w ->
201+
PermEnv -> L.Global -> PermEnv
202+
permEnvAddGlobalConst dlevel w env global =
203+
let sym = show (L.globalSym global) in
204+
debugTrace dlevel ("Global: " ++ sym ++ "; value =\n" ++
205+
maybe "None" ppLLVMValue
206+
(L.globalValue global)) $
207+
maybe env id $
208+
(\x -> case x of
209+
Just _ -> debugTrace dlevel (sym ++ " translated") x
210+
Nothing -> debugTrace dlevel (sym ++ " not translated") x) $
211+
flip runLLVMTransM (env,dlevel) $
212+
do val <- lift $ L.globalValue global
213+
(sh, t) <- translateLLVMValue w (L.globalType global) val
214+
let p = ValPerm_LLVMBlock $ llvmReadBlockOfShape sh
215+
return $ permEnvAddGlobalSyms env
216+
[PermEnvGlobalEntry (GlobalSymbol $ L.globalSym global) p [t]]

0 commit comments

Comments
 (0)