Skip to content

Commit

Permalink
C++ Reference
Browse files Browse the repository at this point in the history
  • Loading branch information
ttreyer committed May 23, 2024
1 parent 79cec8d commit d61b5dd
Show file tree
Hide file tree
Showing 10 changed files with 109 additions and 13 deletions.
10 changes: 7 additions & 3 deletions src/ast/passes/codegen_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1800,7 +1800,8 @@ void CodegenLLVM::unop_ptr(Unop &unop)
switch (unop.op) {
case Operator::MUL: {
if (unop.type.IsIntegerTy() || unop.type.IsPtrTy()) {
auto *et = type.GetPointeeTy();
auto *et = type.IsRefTy() ? type.GetDereferencedType()
: type.GetPointeeTy();
AllocaInst *dst = b_.CreateAllocaBPF(*et, "deref");
b_.CreateProbeRead(ctx_, dst, *et, expr_, unop.loc, type.GetAS());
expr_ = b_.CreateLoad(b_.GetType(*et), dst);
Expand All @@ -1826,7 +1827,10 @@ void CodegenLLVM::visit(Unop &unop)
SizedType &type = unop.expr->type;
if (type.IsIntegerTy()) {
unop_int(unop);
} else if (type.IsPtrTy() || type.IsCtxAccess()) // allow dereferencing args
} else if (type.IsPtrTy() || type.IsRefTy() ||
type.IsCtxAccess()) // allow
// dereferencing
// args
{
unop_ptr(unop);
} else {
Expand Down Expand Up @@ -3791,7 +3795,7 @@ void CodegenLLVM::readDatastructElemFromStack(Value *src_data,
if (src->getType() != dst_type->getPointerTo())
src = b_.CreatePointerCast(src, dst_type->getPointerTo());

if (elem_type.IsIntegerTy() || elem_type.IsPtrTy()) {
if (elem_type.IsIntegerTy() || elem_type.IsPtrTy() || elem_type.IsRefTy()) {
// Load the correct type from src
expr_ = b_.CreateDatastructElemLoad(
elem_type, src, true, elem_type.GetAS());
Expand Down
6 changes: 4 additions & 2 deletions src/ast/passes/field_analyser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,10 @@ void FieldAnalyser::visit(AssignVarStatement &assignment)
void FieldAnalyser::visit(Unop &unop)
{
Visit(*unop.expr);
if (unop.op == Operator::MUL && sized_type_.IsPtrTy()) {
sized_type_ = *sized_type_.GetPointeeTy();
if (unop.op == Operator::MUL &&
(sized_type_.IsPtrTy() || sized_type_.IsRefTy())) {
sized_type_ = sized_type_.IsPtrTy() ? *sized_type_.GetPointeeTy()
: *sized_type_.GetDereferencedType();
resolve_fields(sized_type_);
}
}
Expand Down
51 changes: 47 additions & 4 deletions src/ast/passes/semantic_analyser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ void SemanticAnalyser::visit(Call &call)
}

expr.accept(*this);
dereference_if_needed((*call.vargs)[i]);
}
}

Expand Down Expand Up @@ -1324,6 +1325,7 @@ void SemanticAnalyser::visit(Sizeof &szof)
szof.type = CreateUInt64();
if (szof.expr) {
szof.expr->accept(*this);
dereference_if_needed(szof.expr);
szof.argtype = szof.expr->type;
}
resolve_struct_type(szof.argtype, szof.loc);
Expand All @@ -1334,6 +1336,7 @@ void SemanticAnalyser::visit(Offsetof &ofof)
ofof.type = CreateUInt64();
if (ofof.expr) {
ofof.expr->accept(*this);
dereference_if_needed(ofof.expr);
ofof.record = ofof.expr->type;
}
resolve_struct_type(ofof.record, ofof.loc);
Expand Down Expand Up @@ -1440,6 +1443,7 @@ void SemanticAnalyser::visit(Map &map)
for (unsigned int i = 0; i < map.vargs->size(); i++) {
Expression *expr = map.vargs->at(i);
expr->accept(*this);
dereference_if_needed(map.vargs->at(i));

// Insert a cast to 64 bits if needed by injecting
// a cast into the ast.
Expand Down Expand Up @@ -1508,7 +1512,9 @@ void SemanticAnalyser::visit(Variable &var)
void SemanticAnalyser::visit(ArrayAccess &arr)
{
arr.expr->accept(*this);
dereference_if_needed(arr.expr);
arr.indexpr->accept(*this);
dereference_if_needed(arr.indexpr);

SizedType &type = arr.expr->type;
SizedType &indextype = arr.indexpr->type;
Expand Down Expand Up @@ -1749,7 +1755,10 @@ void SemanticAnalyser::binop_ptr(Binop &binop)
void SemanticAnalyser::visit(Binop &binop)
{
binop.left->accept(*this);
dereference_if_needed(binop.left);

binop.right->accept(*this);
dereference_if_needed(binop.right);

auto &lht = binop.left->type;
auto &rht = binop.right->type;
Expand Down Expand Up @@ -1852,6 +1861,10 @@ void SemanticAnalyser::visit(Unop &unop)
}

unop.expr->accept(*this);
if (!(unop.op == Operator::MUL && unop.expr->type.IsRefTy())) {
// Prevent dereferencing a deref
dereference_if_needed(unop.expr);
}

auto valid_ptr_op = false;
switch (unop.op) {
Expand All @@ -1865,10 +1878,11 @@ void SemanticAnalyser::visit(Unop &unop)

SizedType &type = unop.expr->type;
if (is_final_pass()) {
// Unops are only allowed on ints (e.g. ~$x), dereference only on pointers
// and context (we allow args->field for backwards compatibility)
// Unops are only allowed on ints (e.g. ~$x), dereference only on pointers,
// references and context (we allow args->field for backwards compatibility)
if (!type.IsIntegerTy() &&
!((type.IsPtrTy() || type.IsCtxAccess()) && valid_ptr_op)) {
!((type.IsPtrTy() || type.IsRefTy() || type.IsCtxAccess()) &&
valid_ptr_op)) {
LOG(ERROR, unop.loc, err_)
<< "The " << opstr(unop)
<< " operator can not be used on expressions of type '" << type
Expand Down Expand Up @@ -1920,8 +1934,11 @@ void SemanticAnalyser::visit(Unop &unop)
void SemanticAnalyser::visit(Ternary &ternary)
{
ternary.cond->accept(*this);
dereference_if_needed(ternary.cond);
ternary.left->accept(*this);
dereference_if_needed(ternary.left);
ternary.right->accept(*this);
dereference_if_needed(ternary.right);
const Type &cond = ternary.cond->type.GetTy();
const Type &lhs = ternary.left->type.GetTy();
const Type &rhs = ternary.right->type.GetTy();
Expand Down Expand Up @@ -1949,6 +1966,7 @@ void SemanticAnalyser::visit(Ternary &ternary)
void SemanticAnalyser::visit(If &if_block)
{
if_block.cond->accept(*this);
dereference_if_needed(if_block.cond);

if (is_final_pass()) {
const Type &cond = if_block.cond->type.GetTy();
Expand All @@ -1965,6 +1983,7 @@ void SemanticAnalyser::visit(If &if_block)
void SemanticAnalyser::visit(Unroll &unroll)
{
unroll.expr->accept(*this);
dereference_if_needed(unroll.expr);

auto unroll_value = bpftrace_.get_int_literal(unroll.expr);
if (!unroll_value.has_value()) {
Expand All @@ -1987,8 +2006,10 @@ void SemanticAnalyser::visit(Jump &jump)
{
switch (jump.ident) {
case JumpType::RETURN:
if (jump.return_value)
if (jump.return_value) {
jump.return_value->accept(*this);
dereference_if_needed(jump.return_value);
}
if (auto subprog = dynamic_cast<Subprog *>(scope_)) {
if ((subprog->return_type.IsVoidTy() !=
(jump.return_value == nullptr)) ||
Expand Down Expand Up @@ -2020,6 +2041,7 @@ void SemanticAnalyser::visit(While &while_block)
}

while_block.cond->accept(*this);
dereference_if_needed(while_block.cond);

loop_depth_++;
accept_statements(while_block.stmts);
Expand Down Expand Up @@ -2148,6 +2170,7 @@ void SemanticAnalyser::visit(FieldAccess &acc)
assert((acc.field.size() > 0) != (acc.index >= 0));

acc.expr->accept(*this);
dereference_if_needed(acc.expr);

SizedType &type = acc.expr->type;

Expand Down Expand Up @@ -2285,6 +2308,7 @@ void SemanticAnalyser::visit(FieldAccess &acc)
void SemanticAnalyser::visit(Cast &cast)
{
cast.expr->accept(*this);
dereference_if_needed(cast.expr);

// cast type is synthesised in parser, if it is a struct, it needs resolving
resolve_struct_type(cast.type, cast.loc);
Expand Down Expand Up @@ -2365,6 +2389,7 @@ void SemanticAnalyser::visit(Tuple &tuple)
for (size_t i = 0; i < tuple.elems->size(); ++i) {
Expression *elem = tuple.elems->at(i);
elem->accept(*this);
dereference_if_needed(tuple.elems->at(i));

// If elem type is none that means that the tuple contains some
// invalid cast (e.g., (0, (aaa)0)). In this case, skip the tuple
Expand All @@ -2380,12 +2405,14 @@ void SemanticAnalyser::visit(Tuple &tuple)
void SemanticAnalyser::visit(ExprStatement &expr)
{
expr.expr->accept(*this);
dereference_if_needed(expr.expr);
}

void SemanticAnalyser::visit(AssignMapStatement &assignment)
{
assignment.map->accept(*this);
assignment.expr->accept(*this);
dereference_if_needed(assignment.expr);

assign_map_type(*assignment.map, assignment.expr->type);

Expand Down Expand Up @@ -2462,6 +2489,7 @@ void SemanticAnalyser::visit(AssignMapStatement &assignment)
void SemanticAnalyser::visit(AssignVarStatement &assignment)
{
assignment.expr->accept(*this);
dereference_if_needed(assignment.expr);

std::string var_ident = assignment.var->ident;
auto search = variable_val_[scope_].find(var_ident);
Expand Down Expand Up @@ -2542,11 +2570,13 @@ void SemanticAnalyser::visit(AssignVarStatement &assignment)
void SemanticAnalyser::visit(AssignConfigVarStatement &assignment)
{
assignment.expr->accept(*this);
dereference_if_needed(assignment.expr);
}

void SemanticAnalyser::visit(Predicate &pred)
{
pred.expr->accept(*this);
dereference_if_needed(pred.expr);
if (is_final_pass()) {
SizedType &ty = pred.expr->type;
if (!ty.IsIntTy() && !ty.IsPtrTy()) {
Expand Down Expand Up @@ -3324,5 +3354,18 @@ Pass CreateSemanticPass()
return Pass("Semantic", fn);
};

void SemanticAnalyser::dereference_if_needed(Expression *&expr)
{
const auto &type = expr->type;
if (type.IsRefTy()) {
expr = new Unop(Operator::MUL, expr, expr->loc);
expr->type = *type.GetDereferencedType();
expr->type.is_internal = type.is_internal;
expr->type.SetAS(type.GetAS());
if (type.IsCtxAccess())
expr->type.MarkCtxAccess();
}
}

} // namespace ast
} // namespace bpftrace
1 change: 1 addition & 0 deletions src/ast/passes/semantic_analyser.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ class SemanticAnalyser : public Visitor {
void binop_ptr(Binop &op);
void binop_int(Binop &op);
void binop_array(Binop &op);
void dereference_if_needed(Expression *&expr);

bool has_error() const;
bool in_loop(void)
Expand Down
2 changes: 1 addition & 1 deletion src/dwarf_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ SizedType Dwarf::get_stype(lldb::SBType type, bool resolve_structs)
case lldb::eTypeClassPointer:
return CreatePointer(get_stype(type.GetPointeeType(), false));
case lldb::eTypeClassReference:
return CreatePointer(get_stype(type.GetDereferencedType(), false));
return CreateReference(get_stype(type.GetDereferencedType(), false));
case lldb::eTypeClassClass:
case lldb::eTypeClassStruct:
case lldb::eTypeClassUnion: {
Expand Down
13 changes: 13 additions & 0 deletions src/types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ std::string typestr(Type t)
case Type::voidtype: return "void"; break;
case Type::integer: return "integer"; break;
case Type::pointer: return "pointer"; break;
case Type::reference:return "reference";break;
case Type::record: return "record"; break;
case Type::hist: return "hist"; break;
case Type::lhist: return "lhist"; break;
Expand Down Expand Up @@ -354,6 +355,15 @@ SizedType CreatePointer(const SizedType &pointee_type, AddrSpace as)
return ty;
}

SizedType CreateReference(const SizedType &referred_type, AddrSpace as)
{
// Pointer itself is always an uint64
auto ty = SizedType(Type::reference, 8);
ty.element_type_ = std::make_shared<SizedType>(referred_type);
ty.SetAS(as);
return ty;
}

SizedType CreateRecord(const std::string &name, std::weak_ptr<Struct> record)
{
auto ty = SizedType(Type::record, record.expired() ? 0 : record.lock()->size);
Expand Down Expand Up @@ -584,6 +594,9 @@ size_t hash<bpftrace::SizedType>::operator()(
case bpftrace::Type::pointer:
bpftrace::hash_combine(hash, *type.GetPointeeTy());
break;
case bpftrace::Type::reference:
bpftrace::hash_combine(hash, *type.GetDereferencedType());
break;
case bpftrace::Type::record:
bpftrace::hash_combine(hash, type.GetName());
break;
Expand Down
14 changes: 14 additions & 0 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ enum class Type : uint8_t {
voidtype,
integer,
pointer,
reference,
record, // struct/union, as struct is a protected keyword
hist,
lhist,
Expand Down Expand Up @@ -284,6 +285,12 @@ class SizedType {
return element_type_.get();
}

const SizedType *GetDereferencedType() const
{
assert(IsRefTy());
return element_type_.get();
}

bool IsBoolTy() const
{
return type_ == Type::integer && size_bits_ == 1;
Expand All @@ -292,6 +299,10 @@ class SizedType {
{
return type_ == Type::pointer;
};
bool IsRefTy() const
{
return type_ == Type::reference;
};
bool IsIntTy() const
{
return type_ == Type::integer;
Expand Down Expand Up @@ -422,6 +433,7 @@ class SizedType {
const SizedType &element_type);

friend SizedType CreatePointer(const SizedType &pointee_type, AddrSpace as);
friend SizedType CreateReference(const SizedType &pointee_type, AddrSpace as);
friend SizedType CreateRecord(const std::string &name,
std::weak_ptr<Struct> record);
friend SizedType CreateInteger(size_t bits, bool is_signed);
Expand All @@ -448,6 +460,8 @@ SizedType CreateString(size_t size);
SizedType CreateArray(size_t num_elements, const SizedType &element_type);
SizedType CreatePointer(const SizedType &pointee_type,
AddrSpace as = AddrSpace::none);
SizedType CreateReference(const SizedType &referred_type,
AddrSpace as = AddrSpace::none);

SizedType CreateRecord(const std::string &name, std::weak_ptr<Struct> record);
SizedType CreateTuple(std::weak_ptr<Struct> tuple);
Expand Down
3 changes: 2 additions & 1 deletion tests/data/data_source_cxx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ struct Bottom : public Left, public Right {

struct Multi : public Parent, public Top {
int abc;
int &rabc;

Multi(int a, int b, int c, int d, int e)
: Parent{ a, b, c, d }, Top{ e }, abc{ e + 1 }
: Parent{ a, b, c, d }, Top{ e }, abc{ e + 1 }, rabc{ abc }
{
}
};
Expand Down
9 changes: 7 additions & 2 deletions tests/field_analyser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,8 +610,8 @@ TEST_F(field_analyser_dwarf, parse_inheritance_multi)
}

ASSERT_TRUE(cls->HasFields());
ASSERT_EQ(cls->fields.size(), 6);
ASSERT_EQ(cls->size, 24);
ASSERT_EQ(cls->fields.size(), 7);
ASSERT_EQ(cls->size, 32);

CheckParentFields(cls);

Expand All @@ -624,6 +624,11 @@ TEST_F(field_analyser_dwarf, parse_inheritance_multi)
EXPECT_TRUE(cls->GetField("abc").type.IsIntTy());
EXPECT_EQ(cls->GetField("abc").type.GetSize(), 4);
EXPECT_EQ(cls->GetField("abc").offset, 20);

EXPECT_TRUE(cls->HasField("rabc"));
EXPECT_TRUE(cls->GetField("rabc").type.IsRefTy());
EXPECT_EQ(cls->GetField("rabc").type.GetSize(), 8);
EXPECT_EQ(cls->GetField("rabc").offset, 24);
}

TEST_F(field_analyser_dwarf, parse_struct_anonymous_fields)
Expand Down

0 comments on commit d61b5dd

Please sign in to comment.