diff options
author | Eli Friedman <eli.friedman@gmail.com> | 2009-01-24 22:38:55 +0000 |
---|---|---|
committer | Eli Friedman <eli.friedman@gmail.com> | 2009-01-24 22:38:55 +0000 |
commit | 8549e5dcc868f1c6c75ecd11bd8762a018af9f1d (patch) | |
tree | de2b1182833afa037da69928c226dc5444f48389 /clang | |
parent | 2aa38fea3545e31642c048ebac0f7362b4831946 (diff) | |
download | bcm5719-llvm-8549e5dcc868f1c6c75ecd11bd8762a018af9f1d.tar.gz bcm5719-llvm-8549e5dcc868f1c6c75ecd11bd8762a018af9f1d.zip |
Fix for PR2910: implement CodeGen for non-constant offsetof.
Note that there are still other issues in this area; see PR3396.
llvm-svn: 62942
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/CodeGen/CGExprScalar.cpp | 49 | ||||
-rw-r--r-- | clang/test/CodeGen/offsetof.c | 12 |
2 files changed, 54 insertions, 7 deletions
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 766721e96b4..33c5a6124bd 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -15,6 +15,7 @@ #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Constants.h" @@ -711,13 +712,47 @@ Value *ScalarExprEmitter::VisitUnaryImag(const UnaryOperator *E) { Value *ScalarExprEmitter::VisitUnaryOffsetOf(const UnaryOperator *E) { - int64_t Val = E->evaluateOffsetOf(CGF.getContext()); - - assert(E->getType()->isIntegerType() && "Result type must be an integer!"); - - uint32_t ResultWidth = - static_cast<uint32_t>(CGF.getContext().getTypeSize(E->getType())); - return llvm::ConstantInt::get(llvm::APInt(ResultWidth, Val)); + const Expr* SubExpr = E->getSubExpr(); + const llvm::Type* ResultType = ConvertType(E->getType()); + llvm::Value* Result = llvm::Constant::getNullValue(ResultType); + while (!isa<CompoundLiteralExpr>(SubExpr)) { + if (const MemberExpr *ME = dyn_cast<MemberExpr>(SubExpr)) { + SubExpr = ME->getBase(); + QualType Ty = SubExpr->getType(); + + RecordDecl *RD = Ty->getAsRecordType()->getDecl(); + const ASTRecordLayout &RL = CGF.getContext().getASTRecordLayout(RD); + FieldDecl *FD = cast<FieldDecl>(ME->getMemberDecl()); + + // FIXME: This is linear time. And the fact that we're indexing + // into the layout by position in the record means that we're + // either stuck numbering the fields in the AST or we have to keep + // the linear search (yuck and yuck). + unsigned i = 0; + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; (void)++Field, ++i) { + if (*Field == FD) + break; + } + + llvm::Value* Offset = + llvm::ConstantInt::get(ResultType, RL.getFieldOffset(i) / 8); + Result = Builder.CreateAdd(Result, Offset); + } else if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(SubExpr)) { + SubExpr = ASE->getBase(); + int64_t size = CGF.getContext().getTypeSize(ASE->getType()) / 8; + llvm::Value* ElemSize = llvm::ConstantInt::get(ResultType, size); + llvm::Value* ElemIndex = CGF.EmitScalarExpr(ASE->getIdx()); + bool IndexSigned = ASE->getIdx()->getType()->isSignedIntegerType(); + ElemIndex = Builder.CreateIntCast(ElemIndex, ResultType, IndexSigned); + llvm::Value* Offset = Builder.CreateMul(ElemSize, ElemIndex); + Result = Builder.CreateAdd(Result, Offset); + } else { + assert(0 && "This should be impossible!"); + } + } + return Result; } //===----------------------------------------------------------------------===// diff --git a/clang/test/CodeGen/offsetof.c b/clang/test/CodeGen/offsetof.c new file mode 100644 index 00000000000..7b6f5039f8c --- /dev/null +++ b/clang/test/CodeGen/offsetof.c @@ -0,0 +1,12 @@ +// RUN: clang %s -emit-llvm -o %t + +// PR2910 +struct sockaddr_un { + unsigned char sun_len; + char sun_path[104]; +}; + +int test(int len) { + return __builtin_offsetof(struct sockaddr_un, sun_path[len+1]); +} + |